import React, { useLayoutEffect } from 'react' import { useTranslation } from 'react-i18next' import { ActivityIndicator, Dimensions, LayoutAnimation, Platform, StyleSheet, Text, View, } from 'react-native' import Card from 'src/components/Card' import ClipboardAwarePasteButton from 'src/components/ClipboardAwarePasteButton' import TextInput, { LINE_HEIGHT } from 'src/components/TextInput' import colors from 'src/styles/colors' import { typeScale } from 'src/styles/fonts' import { Spacing } from 'src/styles/styles' import { useClipboard } from 'src/utils/useClipboard' export enum RecoveryPhraseInputStatus { Inputting = 'Inputting', // input enabled Processing = 'Processing', // code validated, now trying to send it } interface Props { status: RecoveryPhraseInputStatus inputValue: string inputPlaceholder: string onInputChange: (value: string) => void shouldShowClipboard: (value: string) => boolean } const AVERAGE_WORD_WIDTH = 80 const AVERAGE_SEED_WIDTH = AVERAGE_WORD_WIDTH * 24 // Estimated number of lines needed to enter the Recovery Phrase const NUMBER_OF_LINES = Math.ceil(AVERAGE_SEED_WIDTH / Dimensions.get('window').width) const testID = 'ImportWalletBackupKeyInputField' export default function RecoveryPhraseInput({ status, inputValue, inputPlaceholder, onInputChange, shouldShowClipboard, }: Props) { const [forceShowingPasteIcon, clipboardContent, getFreshClipboardContent] = useClipboard() const { t } = useTranslation() // LayoutAnimation when switching to/from input useLayoutEffect(() => { LayoutAnimation.easeInEaseOut() }, [status === RecoveryPhraseInputStatus.Inputting]) function shouldShowClipboardInternal() { if (forceShowingPasteIcon) { return true } return ( !inputValue.toLowerCase().startsWith(clipboardContent.toLowerCase()) && shouldShowClipboard(clipboardContent) ) } const showInput = status === RecoveryPhraseInputStatus.Inputting const showStatus = status === RecoveryPhraseInputStatus.Processing const keyboardType = Platform.OS === 'android' ? 'visible-password' : undefined return ( {/* These views cannot be combined as it will cause the shadow to be clipped on iOS */} {t('accountKey')} {showInput ? ( ) : ( {inputValue || ' '} )} {showStatus && ( {showStatus && } )} {showInput && ( )} ) } const styles = StyleSheet.create({ container: { padding: 0, backgroundColor: colors.textInputBackground, borderColor: colors.borderSecondary, borderRadius: Spacing.Smallest8, borderWidth: 1, }, // Applying overflow 'hidden' to `Card` also hides its shadow // that's why we're using a separate container containRadius: { borderRadius: Spacing.Smallest8, overflow: 'hidden', }, contentLong: { flex: 1, flexDirection: 'row', alignItems: 'center', padding: Spacing.Regular16, paddingVertical: Spacing.Small12, }, contentActiveLong: { flexDirection: 'row', alignItems: 'center', padding: Spacing.Regular16, paddingBottom: 4, borderBottomWidth: 1, borderColor: colors.borderSecondary, }, innerContent: { flex: 1, }, labelLong: { ...typeScale.labelSemiBoldSmall, color: colors.contentSecondary, opacity: 0.5, marginBottom: 4, }, labelActiveLong: { ...typeScale.labelSemiBoldSmall, }, codeValueLong: { ...typeScale.bodyMedium, color: colors.contentSecondary, }, statusContainer: { width: 32, marginLeft: 4, }, })