Skip to content

Commit

Permalink
fix(suite-native): use react-native-keyboard-controller for keyboard …
Browse files Browse the repository at this point in the history
…handling
  • Loading branch information
yanascz committed Feb 28, 2025
1 parent 0ec5da3 commit ffa5c82
Show file tree
Hide file tree
Showing 27 changed files with 214 additions and 265 deletions.
2 changes: 1 addition & 1 deletion scripts/list-outdated-dependencies/mobile-dependencies.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion suite-native/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
17 changes: 10 additions & 7 deletions suite-native/app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -80,13 +81,15 @@ const PureApp = () => (
<IntlProvider>
<StoreProvider>
<SentryProvider>
<SafeAreaProvider>
<StylesProvider>
<NavigationContainerWithAnalytics>
<AppComponent />
</NavigationContainerWithAnalytics>
</StylesProvider>
</SafeAreaProvider>
<KeyboardProvider>
<SafeAreaProvider>
<StylesProvider>
<NavigationContainerWithAnalytics>
<AppComponent />
</NavigationContainerWithAnalytics>
</StylesProvider>
</SafeAreaProvider>
</KeyboardProvider>
</SentryProvider>
</StoreProvider>
</IntlProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,28 +127,26 @@ export const AccountImportConfirmFormScreen = ({
</Button>
}
>
<FlashList
data={knownTokens}
renderItem={renderItem}
ListEmptyComponent={null}
ListHeaderComponent={
<>
<AccountImportOverview
balance={accountInfo.balance}
symbol={symbol}
formControl={form.control}
/>
{knownTokens.length > 0 && (
<Box marginTop="sp16" marginBottom="sp8">
<Text variant="titleSmall">
<Translation id="moduleAccountImport.summaryScreen.tokens" />
</Text>
</Box>
)}
</>
}
estimatedItemSize={115}
<AccountImportOverview
balance={accountInfo.balance}
symbol={symbol}
formControl={form.control}
/>
{knownTokens.length > 0 && (
<FlashList
data={knownTokens}
renderItem={renderItem}
ListEmptyComponent={null}
ListHeaderComponent={
<Box marginTop="sp16" marginBottom="sp8">
<Text variant="titleSmall">
<Translation id="moduleAccountImport.summaryScreen.tokens" />
</Text>
</Box>
}
estimatedItemSize={115}
/>
)}
</AccountImportSummaryScreen>
</Form>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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) => (
<Screen
header={<AccountImportScreenHeader />}
footer={
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<ScreenFooterGradient />
<Box marginHorizontal="sp16" marginBottom="sp16">
{footer}
}: AccountImportSummaryScreenProps) => {
const { applyStyle } = useNativeStyles();

return (
<Screen
header={<AccountImportScreenHeader />}
footer={
<>
<ScreenFooterGradient />
<Box style={applyStyle(screenFooterStyle)}>{footer}</Box>
</>
}
focusedInputBottomOffset={114} // space below the label input + button height with vertical margin
>
<VStack spacing="sp32" flex={1}>
<Box flex={1} alignItems="center" justifyContent="center">
<PictogramTitleHeader
variant="success"
icon="coinVerticalCheck"
title={title}
subtitle={subtitle}
/>
</Box>
</KeyboardAvoidingView>
}
>
<VStack spacing="sp32" flex={1}>
<Box flex={1} alignItems="center" justifyContent="center">
<PictogramTitleHeader
variant="success"
icon="coinVerticalCheck"
title={title}
subtitle={subtitle}
/>
</Box>
<Box flex={1} justifyContent="flex-end" testID={testID}>
{children}
</Box>
</VStack>
</Screen>
);
<Box flex={1} testID={testID}>
{children}
</Box>
</VStack>
</Screen>
);
};
22 changes: 9 additions & 13 deletions suite-native/module-accounts-import/src/components/XpubHint.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -36,16 +34,14 @@ export const XpubHint = ({ networkType, handleOpen }: XpubScanHintSheet) => {
);

return (
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<Box style={applyStyle(sheetTriggerStyle)}>
<TextButton
viewLeft="question"
onPress={handleOpen}
data-testID="@accounts-import/sync-coins/xpub-help-link"
>
{buttonTitle}
</TextButton>
</Box>
</KeyboardAvoidingView>
<Box style={applyStyle(sheetTriggerStyle)}>
<TextButton
viewLeft="question"
onPress={handleOpen}
data-testID="@accounts-import/sync-coins/xpub-help-link"
>
{buttonTitle}
</TextButton>
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -176,7 +173,7 @@ export const XpubScanScreen = ({
<Screen
header={<AccountImportScreenHeader closeActionType="back" />}
footer={<XpubHint networkType={networkType} handleOpen={handleOpenHint} />}
extraKeyboardAvoidingViewHeight={EXTRA_KEYBOARD_AVOIDING_VIEW_HEIGHT}
focusedInputBottomOffset={163} // button height with vertical margin + footer height
>
<Card>
<SelectableNetworkItem symbol={networkSymbol} />
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -18,10 +18,7 @@ export const PassphraseContentScreenWrapper = ({
}: PassphraseContentScreenWrapperProps) => (
<Screen header={<PassphraseScreenHeader />}>
<VStack marginTop="sp8" spacing="sp16">
<VStack>
<Text variant="titleMedium">{title}</Text>
{subtitle && <Text>{subtitle}</Text>}
</VStack>
<TitleHeader title={title} subtitle={subtitle} titleVariant="titleMedium" />
{children}
</VStack>
</Screen>
Expand Down
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -23,7 +23,6 @@ import {
AuthorizeDeviceStackRoutes,
RootStackParamList,
StackToStackCompositeNavigationProps,
useScrollView,
} from '@suite-native/navigation';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';

Expand All @@ -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;
Expand All @@ -58,7 +53,6 @@ export const PassphraseForm = ({
noPassphraseEnabled,
}: PassphraseFormProps) => {
const dispatch = useDispatch();
const scrollView = useScrollView();
const formWrapperView = useRef<View>(null);

const [isInputFocused, setIsInputFocused] = useState(false);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -70,18 +71,20 @@ export const PassphraseFormScreen = () => {
};

return (
<PassphraseContentScreenWrapper
title={<Translation id="modulePassphrase.title" />}
subtitle={
<Translation
id="modulePassphrase.subtitle"
values={{
bold: chunks => <Text variant="highlight">{chunks}</Text>,
}}
<Screen header={<PassphraseScreenHeader />}>
<VStack marginTop="sp8" spacing="sp16">
<TitleHeader
title={<Translation id="modulePassphrase.title" />}
subtitle={
<Translation
id="modulePassphrase.subtitle"
values={{
bold: chunks => <Text variant="highlight">{chunks}</Text>,
}}
/>
}
titleVariant="titleMedium"
/>
}
>
<VStack spacing="sp16">
<View
style={applyStyle(animationWrapperStyle)}
onLayout={(event: LayoutChangeEvent) =>
Expand Down Expand Up @@ -158,6 +161,6 @@ export const PassphraseFormScreen = () => {
inputLabel={translate('modulePassphrase.form.createWalletInputLabel')}
/>
</VStack>
</PassphraseContentScreenWrapper>
</Screen>
);
};
Loading

0 comments on commit ffa5c82

Please sign in to comment.