Merge pull request #6950 from BlueWallet/memorycon

FIX: memory consumption bug by RN component
This commit is contained in:
GLaDOS 2024-08-21 08:43:55 +00:00 committed by GitHub
commit e55b4ac446
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 628 additions and 682 deletions

View file

@ -7,7 +7,6 @@ import {
I18nManager, I18nManager,
InputAccessoryView, InputAccessoryView,
Keyboard, Keyboard,
KeyboardAvoidingView,
Platform, Platform,
StyleSheet, StyleSheet,
TextInput, TextInput,
@ -188,7 +187,7 @@ export const BlueDoneAndDismissKeyboardInputAccessory = props => {
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
return <InputAccessoryView nativeID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}>{inputView}</InputAccessoryView>; return <InputAccessoryView nativeID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}>{inputView}</InputAccessoryView>;
} else { } else {
return <KeyboardAvoidingView>{inputView}</KeyboardAvoidingView>; return inputView;
} }
}; };

View file

@ -5,7 +5,6 @@ import {
I18nManager, I18nManager,
Image, Image,
Keyboard, Keyboard,
KeyboardAvoidingView,
Platform, Platform,
StyleSheet, StyleSheet,
Text, Text,
@ -397,33 +396,31 @@ const LNDCreateInvoice = () => {
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}> <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
<View style={[styles.root, styleHooks.root]}> <View style={[styles.root, styleHooks.root]}>
<View style={[styles.amount, styleHooks.amount]}> <View style={[styles.amount, styleHooks.amount]}>
<KeyboardAvoidingView enabled={!Platform.isPad} behavior="position"> <AmountInput
<AmountInput isLoading={isLoading}
isLoading={isLoading} amount={amount}
amount={amount} onAmountUnitChange={setUnit}
onAmountUnitChange={setUnit} onChangeText={setAmount}
onChangeText={setAmount} disabled={isLoading || (lnurlParams && lnurlParams.fixed)}
disabled={isLoading || (lnurlParams && lnurlParams.fixed)} unit={unit}
unit={unit} inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
/>
<View style={[styles.fiat, styleHooks.fiat]}>
<TextInput
onChangeText={setDescription}
placeholder={loc.receive.details_label}
value={description}
numberOfLines={1}
placeholderTextColor="#81868e"
style={styles.fiat2}
editable={!isLoading}
onSubmitEditing={Keyboard.dismiss}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID} inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
/> />
<View style={[styles.fiat, styleHooks.fiat]}> {lnurlParams ? null : renderScanClickable()}
<TextInput </View>
onChangeText={setDescription} <BlueDismissKeyboardInputAccessory />
placeholder={loc.receive.details_label} {renderCreateButton()}
value={description}
numberOfLines={1}
placeholderTextColor="#81868e"
style={styles.fiat2}
editable={!isLoading}
onSubmitEditing={Keyboard.dismiss}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
/>
{lnurlParams ? null : renderScanClickable()}
</View>
<BlueDismissKeyboardInputAccessory />
{renderCreateButton()}
</KeyboardAvoidingView>
</View> </View>
{renderWalletSelectionButton()} {renderWalletSelectionButton()}
</View> </View>

View file

@ -1,17 +1,6 @@
import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native'; import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { import { ActivityIndicator, I18nManager, Keyboard, Platform, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
ActivityIndicator,
I18nManager,
Keyboard,
KeyboardAvoidingView,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { Icon } from '@rneui/themed'; import { Icon } from '@rneui/themed';
import { btcToSatoshi, fiatToBTC } from '../../blue_modules/currency'; import { btcToSatoshi, fiatToBTC } from '../../blue_modules/currency';
@ -302,62 +291,67 @@ const ScanLndInvoice = () => {
return ( return (
<SafeArea style={stylesHook.root}> <SafeArea style={stylesHook.root}>
<View style={[styles.root, stylesHook.root]}> <View style={[styles.root, stylesHook.root]}>
<ScrollView contentContainerStyle={styles.scroll} keyboardShouldPersistTaps="handled"> <ScrollView
<KeyboardAvoidingView enabled behavior="position" keyboardVerticalOffset={20}> contentContainerStyle={styles.scroll}
<View style={styles.scrollMargin}> keyboardShouldPersistTaps="handled"
<AmountInput automaticallyAdjustContentInsets
pointerEvents={isAmountInitiallyEmpty ? 'auto' : 'none'} automaticallyAdjustKeyboardInsets
isLoading={isLoading} contentInsetAdjustmentBehavior="automatic"
amount={amount} >
onAmountUnitChange={setUnit} <View style={styles.scrollMargin}>
onChangeText={setAmount} <AmountInput
disabled={!decoded || isLoading || decoded.num_satoshis > 0} pointerEvents={isAmountInitiallyEmpty ? 'auto' : 'none'}
unit={unit} isLoading={isLoading}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID} amount={amount}
/> onAmountUnitChange={setUnit}
</View> onChangeText={setAmount}
disabled={!decoded || isLoading || decoded.num_satoshis > 0}
unit={unit}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
/>
</View>
<BlueCard> <BlueCard>
<AddressInput <AddressInput
onChangeText={text => { onChangeText={text => {
text = text.trim(); text = text.trim();
setDestination(text); setDestination(text);
}} }}
onBarScanned={data => processTextForInvoice(data.data)} onBarScanned={data => processTextForInvoice(data.data)}
address={destination} address={destination}
isLoading={isLoading} isLoading={isLoading}
placeholder={loc.lnd.placeholder} placeholder={loc.lnd.placeholder}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID} inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
launchedBy={name} launchedBy={name}
onBlur={onBlur} onBlur={onBlur}
keyboardType="email-address" keyboardType="email-address"
/> />
<View style={styles.description}> <View style={styles.description}>
<Text numberOfLines={0} style={styles.descriptionText}> <Text numberOfLines={0} style={styles.descriptionText}>
{decoded !== undefined ? decoded.description : ''} {decoded !== undefined ? decoded.description : ''}
</Text> </Text>
</View>
{expiresIn !== undefined && (
<View>
<Text style={styles.expiresIn}>{expiresIn}</Text>
{decoded && decoded.num_satoshis > 0 && (
<Text style={styles.expiresIn}>{loc.formatString(loc.lnd.potentialFee, { fee: getFees() })}</Text>
)}
</View> </View>
{expiresIn !== undefined && ( )}
<BlueCard>
{isLoading ? (
<View> <View>
<Text style={styles.expiresIn}>{expiresIn}</Text> <ActivityIndicator />
{decoded && decoded.num_satoshis > 0 && ( </View>
<Text style={styles.expiresIn}>{loc.formatString(loc.lnd.potentialFee, { fee: getFees() })}</Text> ) : (
)} <View>
<Button title={loc.lnd.payButton} onPress={pay} disabled={shouldDisablePayButton()} />
</View> </View>
)} )}
<BlueCard>
{isLoading ? (
<View>
<ActivityIndicator />
</View>
) : (
<View>
<Button title={loc.lnd.payButton} onPress={pay} disabled={shouldDisablePayButton()} />
</View>
)}
</BlueCard>
</BlueCard> </BlueCard>
</KeyboardAvoidingView> </BlueCard>
{renderWalletSelectionButton()} {renderWalletSelectionButton()}
</ScrollView> </ScrollView>
</View> </View>

View file

@ -1,10 +1,9 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useRoute, RouteProp } from '@react-navigation/native'; import { useRoute, RouteProp } from '@react-navigation/native';
import * as bitcoin from 'bitcoinjs-lib'; import * as bitcoin from 'bitcoinjs-lib';
import { ActivityIndicator, Keyboard, KeyboardAvoidingView, Linking, Platform, StyleSheet, TextInput, View } from 'react-native'; import { ActivityIndicator, Keyboard, Linking, StyleSheet, TextInput, View } from 'react-native';
import * as BlueElectrum from '../../blue_modules/BlueElectrum'; import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import { isTablet } from '../../blue_modules/environment';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import Notifications from '../../blue_modules/notifications'; import Notifications from '../../blue_modules/notifications';
import { import {
@ -125,44 +124,42 @@ const Broadcast: React.FC = () => {
return ( return (
<SafeArea> <SafeArea>
<KeyboardAvoidingView enabled={!isTablet} behavior={Platform.OS === 'ios' ? 'position' : undefined}> <View style={styles.wrapper} testID="BroadcastView">
<View style={styles.wrapper} testID="BroadcastView"> {BROADCAST_RESULT.success !== broadcastResult && (
{BROADCAST_RESULT.success !== broadcastResult && ( <BlueCard style={styles.mainCard}>
<BlueCard style={styles.mainCard}> <View style={styles.topFormRow}>
<View style={styles.topFormRow}> <BlueFormLabel>{status}</BlueFormLabel>
<BlueFormLabel>{status}</BlueFormLabel> {BROADCAST_RESULT.pending === broadcastResult && <ActivityIndicator size="small" />}
{BROADCAST_RESULT.pending === broadcastResult && <ActivityIndicator size="small" />} </View>
</View>
<View style={[styles.input, stylesHooks.input]}> <View style={[styles.input, stylesHooks.input]}>
<TextInput <TextInput
style={styles.text} style={styles.text}
multiline multiline
editable editable
placeholderTextColor="#81868e" placeholderTextColor="#81868e"
value={txHex} value={txHex}
onChangeText={handleUpdateTxHex} onChangeText={handleUpdateTxHex}
onSubmitEditing={Keyboard.dismiss} onSubmitEditing={Keyboard.dismiss}
testID="TxHex" testID="TxHex"
/>
</View>
<BlueSpacing20 />
<Button title={loc.multisig.scan_or_open_file} onPress={handleQRScan} />
<BlueSpacing20 />
<Button
title={loc.send.broadcastButton}
onPress={handleBroadcast}
disabled={broadcastResult === BROADCAST_RESULT.pending || txHex?.length === 0 || txHex === undefined}
testID="BroadcastButton"
/> />
<BlueSpacing20 /> </View>
</BlueCard> <BlueSpacing20 />
)}
{BROADCAST_RESULT.success === broadcastResult && tx && <SuccessScreen tx={tx} />} <Button title={loc.multisig.scan_or_open_file} onPress={handleQRScan} />
</View> <BlueSpacing20 />
</KeyboardAvoidingView>
<Button
title={loc.send.broadcastButton}
onPress={handleBroadcast}
disabled={broadcastResult === BROADCAST_RESULT.pending || txHex?.length === 0 || txHex === undefined}
testID="BroadcastButton"
/>
<BlueSpacing20 />
</BlueCard>
)}
{BROADCAST_RESULT.success === broadcastResult && tx && <SuccessScreen tx={tx} />}
</View>
</SafeArea> </SafeArea>
); );
}; };

View file

@ -10,7 +10,6 @@ import {
FlatList, FlatList,
I18nManager, I18nManager,
Keyboard, Keyboard,
KeyboardAvoidingView,
LayoutAnimation, LayoutAnimation,
NativeScrollEvent, NativeScrollEvent,
NativeSyntheticEvent, NativeSyntheticEvent,
@ -50,7 +49,6 @@ import { TOptions } from 'bip21';
import assert from 'assert'; import assert from 'assert';
import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { SendDetailsStackParamList } from '../../navigation/SendDetailsStackParamList'; import { SendDetailsStackParamList } from '../../navigation/SendDetailsStackParamList';
import { isTablet } from '../../blue_modules/environment';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation'; import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { ContactList } from '../../class/contact-list'; import { ContactList } from '../../class/contact-list';
import { useStorage } from '../../hooks/context/useStorage'; import { useStorage } from '../../hooks/context/useStorage';
@ -1324,66 +1322,65 @@ const SendDetails = () => {
return ( return (
<View style={[styles.root, stylesHook.root]} onLayout={e => setWidth(e.nativeEvent.layout.width)}> <View style={[styles.root, stylesHook.root]} onLayout={e => setWidth(e.nativeEvent.layout.width)}>
<View> <View>
<KeyboardAvoidingView enabled={!isTablet} behavior="position"> <FlatList
<FlatList keyboardShouldPersistTaps="always"
keyboardShouldPersistTaps="always" scrollEnabled={addresses.length > 1}
scrollEnabled={addresses.length > 1} data={addresses}
data={addresses} renderItem={renderBitcoinTransactionInfoFields}
renderItem={renderBitcoinTransactionInfoFields} horizontal
horizontal ref={scrollView}
ref={scrollView} automaticallyAdjustKeyboardInsets
pagingEnabled pagingEnabled
removeClippedSubviews={false} removeClippedSubviews={false}
onMomentumScrollBegin={Keyboard.dismiss} onMomentumScrollBegin={Keyboard.dismiss}
onScroll={handleRecipientsScroll} onScroll={handleRecipientsScroll}
scrollEventThrottle={16} scrollEventThrottle={16}
scrollIndicatorInsets={styles.scrollViewIndicator} scrollIndicatorInsets={styles.scrollViewIndicator}
contentContainerStyle={styles.scrollViewContent} contentContainerStyle={styles.scrollViewContent}
getItemLayout={getItemLayout} getItemLayout={getItemLayout}
/>
<View style={[styles.memo, stylesHook.memo]}>
<TextInput
onChangeText={setTransactionMemo}
placeholder={loc.send.details_note_placeholder}
placeholderTextColor="#81868e"
value={transactionMemo}
numberOfLines={1}
style={styles.memoText}
editable={!isLoading}
onSubmitEditing={Keyboard.dismiss}
/* @ts-ignore marcos fixme */
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
/> />
<View style={[styles.memo, stylesHook.memo]}> </View>
<TextInput <TouchableOpacity
onChangeText={setTransactionMemo} testID="chooseFee"
placeholder={loc.send.details_note_placeholder} accessibilityRole="button"
placeholderTextColor="#81868e" onPress={() => feeModalRef.current?.present()}
value={transactionMemo} disabled={isLoading}
numberOfLines={1} style={styles.fee}
style={styles.memoText} >
editable={!isLoading} <Text style={[styles.feeLabel, stylesHook.feeLabel]}>{loc.send.create_fee}</Text>
onSubmitEditing={Keyboard.dismiss}
/* @ts-ignore marcos fixme */
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
/>
</View>
<TouchableOpacity
testID="chooseFee"
accessibilityRole="button"
onPress={() => feeModalRef.current?.present()}
disabled={isLoading}
style={styles.fee}
>
<Text style={[styles.feeLabel, stylesHook.feeLabel]}>{loc.send.create_fee}</Text>
{networkTransactionFeesIsLoading ? ( {networkTransactionFeesIsLoading ? (
<ActivityIndicator /> <ActivityIndicator />
) : ( ) : (
<View style={[styles.feeRow, stylesHook.feeRow]}> <View style={[styles.feeRow, stylesHook.feeRow]}>
<Text style={stylesHook.feeValue}> <Text style={stylesHook.feeValue}>
{feePrecalc.current ? formatFee(feePrecalc.current) : feeRate + ' ' + loc.units.sat_vbyte} {feePrecalc.current ? formatFee(feePrecalc.current) : feeRate + ' ' + loc.units.sat_vbyte}
</Text> </Text>
</View> </View>
)} )}
</TouchableOpacity> </TouchableOpacity>
{renderCreateButton()} {renderCreateButton()}
<SelectFeeModal <SelectFeeModal
ref={feeModalRef} ref={feeModalRef}
networkTransactionFees={networkTransactionFees} networkTransactionFees={networkTransactionFees}
feePrecalc={feePrecalc} feePrecalc={feePrecalc}
feeRate={feeRate} feeRate={feeRate}
setCustomFee={setCustomFee} setCustomFee={setCustomFee}
setFeePrecalc={setFeePrecalc} setFeePrecalc={setFeePrecalc}
/> />
</KeyboardAvoidingView>
</View> </View>
<BlueDismissKeyboardInputAccessory /> <BlueDismissKeyboardInputAccessory />
{Platform.select({ {Platform.select({

View file

@ -1,6 +1,6 @@
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import { useRoute } from '@react-navigation/native'; import { useRoute } from '@react-navigation/native';
import { Keyboard, KeyboardAvoidingView, Platform, StyleSheet, TextInput, View } from 'react-native'; import { Keyboard, StyleSheet, TextInput, View } from 'react-native';
import { BlueButtonLink, BlueCard, BlueSpacing10, BlueSpacing20, BlueText } from '../../BlueComponents'; import { BlueButtonLink, BlueCard, BlueSpacing10, BlueSpacing20, BlueText } from '../../BlueComponents';
import Button from '../../components/Button'; import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea'; import SafeArea from '../../components/SafeArea';
@ -86,52 +86,46 @@ const IsItMyAddress = () => {
return ( return (
<SafeArea style={styles.blueArea}> <SafeArea style={styles.blueArea}>
<KeyboardAvoidingView <View style={styles.wrapper}>
enabled={!Platform.isPad} <BlueCard style={styles.mainCard}>
behavior={Platform.OS === 'ios' ? 'position' : null} <View style={[styles.input, stylesHooks.input]}>
keyboardShouldPersistTaps="handled" <TextInput
> style={styles.text}
<View style={styles.wrapper}> maxHeight={100}
<BlueCard style={styles.mainCard}> minHeight={100}
<View style={[styles.input, stylesHooks.input]}> maxWidth="100%"
<TextInput minWidth="100%"
style={styles.text} multiline
maxHeight={100} editable
minHeight={100} placeholder={loc.is_it_my_address.enter_address}
maxWidth="100%" placeholderTextColor="#81868e"
minWidth="100%" value={address}
multiline onChangeText={handleUpdateAddress}
editable testID="AddressInput"
placeholder={loc.is_it_my_address.enter_address}
placeholderTextColor="#81868e"
value={address}
onChangeText={handleUpdateAddress}
testID="AddressInput"
/>
</View>
<BlueSpacing10 />
<BlueButtonLink ref={scanButtonRef} title={loc.wallets.import_scan_qr} onPress={importScan} />
<BlueSpacing10 />
<Button title={loc.send.input_clear} onPress={clearAddressInput} />
<BlueSpacing20 />
{resultCleanAddress && (
<>
<Button title={loc.is_it_my_address.view_qrcode} onPress={viewQRCode} />
<BlueSpacing20 />
</>
)}
<Button
disabled={address.trim().length === 0}
title={loc.is_it_my_address.check_address}
onPress={checkAddress}
testID="CheckAddress"
/> />
<BlueSpacing20 /> </View>
<BlueText testID="Result">{result}</BlueText>
</BlueCard> <BlueSpacing10 />
</View> <BlueButtonLink ref={scanButtonRef} title={loc.wallets.import_scan_qr} onPress={importScan} />
</KeyboardAvoidingView> <BlueSpacing10 />
<Button title={loc.send.input_clear} onPress={clearAddressInput} />
<BlueSpacing20 />
{resultCleanAddress && (
<>
<Button title={loc.is_it_my_address.view_qrcode} onPress={viewQRCode} />
<BlueSpacing20 />
</>
)}
<Button
disabled={address.trim().length === 0}
title={loc.is_it_my_address.check_address}
onPress={checkAddress}
testID="CheckAddress"
/>
<BlueSpacing20 />
<BlueText testID="Result">{result}</BlueText>
</BlueCard>
</View>
</SafeArea> </SafeArea>
); );
}; };

View file

@ -4,7 +4,6 @@ import React, { Component } from 'react';
import { import {
Alert, Alert,
Keyboard, Keyboard,
KeyboardAvoidingView,
Platform, Platform,
Pressable, Pressable,
ScrollView, ScrollView,
@ -284,113 +283,111 @@ export default class ElectrumSettings extends Component {
{this.state.config.host}:{this.state.config.port} {this.state.config.host}:{this.state.config.port}
</BlueText> </BlueText>
</BlueCard> </BlueCard>
<KeyboardAvoidingView> <BlueCard>
<BlueCard> <View style={styles.inputWrap}>
<TextInput
placeholder={loc.formatString(loc.settings.electrum_host, { example: '10.20.30.40' })}
value={this.state.host}
onChangeText={text => {
const host = text.trim();
this.setState({ host }, () => {
if (host.endsWith('.onion')) {
this.useSSLPortToggled(false);
}
});
}}
numberOfLines={1}
style={styles.inputText}
editable={!this.state.isLoading}
placeholderTextColor="#81868e"
autoCorrect={false}
autoCapitalize="none"
underlineColorAndroid="transparent"
inputAccessoryViewID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}
testID="HostInput"
onFocus={() => this.setState({ isAndroidAddressKeyboardVisible: true })}
onBlur={() => this.setState({ isAndroidAddressKeyboardVisible: false })}
/>
</View>
<BlueSpacing20 />
<View style={styles.portWrap}>
<View style={styles.inputWrap}> <View style={styles.inputWrap}>
<TextInput <TextInput
placeholder={loc.formatString(loc.settings.electrum_host, { example: '10.20.30.40' })} placeholder={loc.formatString(loc.settings.electrum_port, { example: '50001' })}
value={this.state.host} value={this.state.sslPort?.trim() === '' || this.state.sslPort === null ? this.state.port : this.state.sslPort}
onChangeText={text => { onChangeText={text =>
const host = text.trim(); this.setState(prevState => {
this.setState({ host }, () => { if (prevState.sslPort?.trim() === '') {
if (host.endsWith('.onion')) { return { port: text.trim(), sslPort: '' };
this.useSSLPortToggled(false); } else {
return { port: '', sslPort: text.trim() };
} }
}); })
}} }
numberOfLines={1} numberOfLines={1}
style={styles.inputText} style={styles.inputText}
editable={!this.state.isLoading} editable={!this.state.isLoading}
placeholderTextColor="#81868e" placeholderTextColor="#81868e"
underlineColorAndroid="transparent"
autoCorrect={false} autoCorrect={false}
autoCapitalize="none" autoCapitalize="none"
underlineColorAndroid="transparent" keyboardType="number-pad"
inputAccessoryViewID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID} inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
testID="HostInput" testID="PortInput"
onFocus={() => this.setState({ isAndroidAddressKeyboardVisible: true })} onFocus={() => this.setState({ isAndroidNumericKeyboardFocused: true })}
onBlur={() => this.setState({ isAndroidAddressKeyboardVisible: false })} onBlur={() => this.setState({ isAndroidNumericKeyboardFocused: false })}
/> />
</View> </View>
<BlueSpacing20 /> <BlueText style={styles.usePort}>{loc.settings.use_ssl}</BlueText>
<View style={styles.portWrap}> <Switch
<View style={styles.inputWrap}> testID="SSLPortInput"
<TextInput value={this.state.sslPort?.trim() > 0}
placeholder={loc.formatString(loc.settings.electrum_port, { example: '50001' })} onValueChange={this.useSSLPortToggled}
value={this.state.sslPort?.trim() === '' || this.state.sslPort === null ? this.state.port : this.state.sslPort} disabled={this.state.host?.endsWith('.onion') ?? false}
onChangeText={text => />
this.setState(prevState => { </View>
if (prevState.sslPort?.trim() === '') { <BlueSpacing20 />
return { port: text.trim(), sslPort: '' };
} else {
return { port: '', sslPort: text.trim() };
}
})
}
numberOfLines={1}
style={styles.inputText}
editable={!this.state.isLoading}
placeholderTextColor="#81868e"
underlineColorAndroid="transparent"
autoCorrect={false}
autoCapitalize="none"
keyboardType="number-pad"
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
testID="PortInput"
onFocus={() => this.setState({ isAndroidNumericKeyboardFocused: true })}
onBlur={() => this.setState({ isAndroidNumericKeyboardFocused: false })}
/>
</View>
<BlueText style={styles.usePort}>{loc.settings.use_ssl}</BlueText>
<Switch
testID="SSLPortInput"
value={this.state.sslPort?.trim() > 0}
onValueChange={this.useSSLPortToggled}
disabled={this.state.host?.endsWith('.onion') ?? false}
/>
</View>
<BlueSpacing20 />
<View style={styles.serverAddTitle}> <View style={styles.serverAddTitle}>
<BlueText style={styles.explain}>{loc.settings.electrum_settings_explain}</BlueText> <BlueText style={styles.explain}>{loc.settings.electrum_settings_explain}</BlueText>
<TouchableOpacity accessibilityRole="button" testID="ResetToDefault" onPress={() => this.resetToDefault()}> <TouchableOpacity accessibilityRole="button" testID="ResetToDefault" onPress={() => this.resetToDefault()}>
<BlueText>{loc.settings.electrum_reset}</BlueText> <BlueText>{loc.settings.electrum_reset}</BlueText>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<BlueSpacing20 /> <BlueSpacing20 />
{this.state.isLoading ? <BlueLoading /> : <Button testID="Save" onPress={this.save} title={loc.settings.save} />} {this.state.isLoading ? <BlueLoading /> : <Button testID="Save" onPress={this.save} title={loc.settings.save} />}
<BlueSpacing20 /> <BlueSpacing20 />
<BlueButtonLink title={loc.wallets.import_scan_qr} onPress={this.importScan} /> <BlueButtonLink title={loc.wallets.import_scan_qr} onPress={this.importScan} />
<BlueSpacing20 /> <BlueSpacing20 />
</BlueCard> </BlueCard>
{Platform.select({ {Platform.select({
ios: <BlueDismissKeyboardInputAccessory />, ios: <BlueDismissKeyboardInputAccessory />,
android: this.state.isAndroidNumericKeyboardFocused && <BlueDismissKeyboardInputAccessory />, android: this.state.isAndroidNumericKeyboardFocused && <BlueDismissKeyboardInputAccessory />,
})} })}
{Platform.select({ {Platform.select({
ios: ( ios: (
<BlueDoneAndDismissKeyboardInputAccessory <BlueDoneAndDismissKeyboardInputAccessory
onClearTapped={() => this.setState({ host: '' })} onClearTapped={() => this.setState({ host: '' })}
onPasteTapped={text => { onPasteTapped={text => {
this.setState({ host: text }); this.setState({ host: text });
Keyboard.dismiss(); Keyboard.dismiss();
}} }}
/> />
), ),
android: this.state.isAndroidAddressKeyboardVisible && ( android: this.state.isAndroidAddressKeyboardVisible && (
<BlueDoneAndDismissKeyboardInputAccessory <BlueDoneAndDismissKeyboardInputAccessory
onClearTapped={() => { onClearTapped={() => {
this.setState({ host: '' }); this.setState({ host: '' });
Keyboard.dismiss(); Keyboard.dismiss();
}} }}
onPasteTapped={text => { onPasteTapped={text => {
this.setState({ host: text }); this.setState({ host: text });
Keyboard.dismiss(); Keyboard.dismiss();
}} }}
/> />
), ),
})} })}
</KeyboardAvoidingView>
{serverHistoryItems.length > 0 && !this.state.isLoading && ( {serverHistoryItems.length > 0 && !this.state.isLoading && (
<BlueCard> <BlueCard>
<View style={styles.serverHistoryTitle}> <View style={styles.serverHistoryTitle}>
@ -408,7 +405,12 @@ export default class ElectrumSettings extends Component {
render() { render() {
return ( return (
<ScrollView keyboardShouldPersistTaps="always" automaticallyAdjustContentInsets contentInsetAdjustmentBehavior="automatic"> <ScrollView
keyboardShouldPersistTaps="always"
automaticallyAdjustContentInsets
contentInsetAdjustmentBehavior="automatic"
automaticallyAdjustKeyboardInsets
>
<ListItem <ListItem
Component={Pressable} Component={Pressable}
title={loc.settings.electrum_offline_mode} title={loc.settings.electrum_offline_mode}

View file

@ -1,15 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { import { ActivityIndicator, Linking, ScrollView, StyleSheet, TextInput, TouchableOpacity, View } from 'react-native';
ActivityIndicator,
KeyboardAvoidingView,
Linking,
Platform,
ScrollView,
StyleSheet,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard'; import Clipboard from '@react-native-clipboard/clipboard';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Text } from '@rneui/themed'; import { Text } from '@rneui/themed';
@ -161,22 +151,20 @@ export default class CPFP extends Component {
renderStage1(text) { renderStage1(text) {
return ( return (
<KeyboardAvoidingView enabled={!Platform.isPad} behavior="position"> <SafeArea style={styles.root}>
<SafeArea style={styles.root}> <BlueSpacing />
<BlueCard style={styles.center}>
<BlueText>{text}</BlueText>
<BlueSpacing20 />
<ReplaceFeeSuggestions onFeeSelected={fee => this.setState({ newFeeRate: fee })} transactionMinimum={this.state.feeRate} />
<BlueSpacing /> <BlueSpacing />
<BlueCard style={styles.center}> <Button
<BlueText>{text}</BlueText> disabled={this.state.newFeeRate <= this.state.feeRate}
<BlueSpacing20 /> onPress={() => this.createTransaction()}
<ReplaceFeeSuggestions onFeeSelected={fee => this.setState({ newFeeRate: fee })} transactionMinimum={this.state.feeRate} /> title={loc.transactions.cpfp_create}
<BlueSpacing /> />
<Button </BlueCard>
disabled={this.state.newFeeRate <= this.state.feeRate} </SafeArea>
onPress={() => this.createTransaction()}
title={loc.transactions.cpfp_create}
/>
</BlueCard>
</SafeArea>
</KeyboardAvoidingView>
); );
} }

View file

@ -5,7 +5,6 @@ import {
ActivityIndicator, ActivityIndicator,
Alert, Alert,
Keyboard, Keyboard,
KeyboardAvoidingView,
LayoutAnimation, LayoutAnimation,
Platform, Platform,
ScrollView, ScrollView,
@ -351,131 +350,129 @@ const WalletsAdd: React.FC = () => {
}; };
return ( return (
<ScrollView style={stylesHook.root} testID="ScrollView"> <ScrollView style={stylesHook.root} testID="ScrollView" automaticallyAdjustKeyboardInsets>
<BlueSpacing20 /> <BlueSpacing20 />
<KeyboardAvoidingView enabled behavior={Platform.OS === 'ios' ? 'padding' : undefined} keyboardVerticalOffset={62}> <BlueFormLabel>{loc.wallets.add_wallet_name}</BlueFormLabel>
<BlueFormLabel>{loc.wallets.add_wallet_name}</BlueFormLabel> <View style={[styles.label, stylesHook.label]}>
<View style={[styles.label, stylesHook.label]}> <TextInput
<TextInput testID="WalletNameInput"
testID="WalletNameInput" value={label}
value={label} placeholderTextColor="#81868e"
placeholderTextColor="#81868e" placeholder={loc.wallets.add_placeholder}
placeholder={loc.wallets.add_placeholder} onChangeText={setLabel}
onChangeText={setLabel} style={styles.textInputCommon}
style={styles.textInputCommon} editable={!isLoading}
editable={!isLoading} underlineColorAndroid="transparent"
underlineColorAndroid="transparent" />
/> </View>
</View> <BlueFormLabel>{loc.wallets.add_wallet_type}</BlueFormLabel>
<BlueFormLabel>{loc.wallets.add_wallet_type}</BlueFormLabel> <View style={styles.buttons}>
<View style={styles.buttons}> <WalletButton
<WalletButton buttonType="Bitcoin"
buttonType="Bitcoin" testID="ActivateBitcoinButton"
testID="ActivateBitcoinButton" active={selectedWalletType === ButtonSelected.ONCHAIN}
active={selectedWalletType === ButtonSelected.ONCHAIN} onPress={handleOnBitcoinButtonPressed}
onPress={handleOnBitcoinButtonPressed} size={styles.button}
size={styles.button} />
/> <WalletButton
<WalletButton buttonType="Lightning"
buttonType="Lightning" active={selectedWalletType === ButtonSelected.OFFCHAIN}
active={selectedWalletType === ButtonSelected.OFFCHAIN} onPress={handleOnLightningButtonPressed}
onPress={handleOnLightningButtonPressed} size={styles.button}
size={styles.button} />
/> <WalletButton
<WalletButton buttonType="Vault"
buttonType="Vault" testID="ActivateVaultButton"
testID="ActivateVaultButton" active={selectedWalletType === ButtonSelected.VAULT}
active={selectedWalletType === ButtonSelected.VAULT} onPress={handleOnVaultButtonPressed}
onPress={handleOnVaultButtonPressed} size={styles.button}
size={styles.button} />
/> </View>
</View>
<View style={styles.advanced}> <View style={styles.advanced}>
{(() => { {(() => {
if (selectedWalletType === ButtonSelected.ONCHAIN && isAdvancedModeEnabled) { if (selectedWalletType === ButtonSelected.ONCHAIN && isAdvancedModeEnabled) {
return ( return (
<View> <View>
<BlueSpacing20 /> <BlueSpacing20 />
<Text style={[styles.advancedText, stylesHook.advancedText]}>{loc.settings.advanced_options}</Text> <Text style={[styles.advancedText, stylesHook.advancedText]}>{loc.settings.advanced_options}</Text>
<ListItem <ListItem
containerStyle={[styles.noPadding, stylesHook.noPadding]} containerStyle={[styles.noPadding, stylesHook.noPadding]}
bottomDivider={false} bottomDivider={false}
onPress={() => setSelectedIndex(0)} onPress={() => setSelectedIndex(0)}
title={HDSegwitBech32Wallet.typeReadable} title={HDSegwitBech32Wallet.typeReadable}
checkmark={selectedIndex === 0} checkmark={selectedIndex === 0}
/> />
<ListItem <ListItem
containerStyle={[styles.noPadding, stylesHook.noPadding]} containerStyle={[styles.noPadding, stylesHook.noPadding]}
bottomDivider={false} bottomDivider={false}
onPress={() => setSelectedIndex(1)} onPress={() => setSelectedIndex(1)}
title={SegwitP2SHWallet.typeReadable} title={SegwitP2SHWallet.typeReadable}
checkmark={selectedIndex === 1} checkmark={selectedIndex === 1}
/> />
<ListItem <ListItem
containerStyle={[styles.noPadding, stylesHook.noPadding]} containerStyle={[styles.noPadding, stylesHook.noPadding]}
bottomDivider={false} bottomDivider={false}
onPress={() => setSelectedIndex(2)} onPress={() => setSelectedIndex(2)}
title={HDSegwitP2SHWallet.typeReadable} title={HDSegwitP2SHWallet.typeReadable}
checkmark={selectedIndex === 2} checkmark={selectedIndex === 2}
/>
</View>
);
} else if (selectedWalletType === ButtonSelected.OFFCHAIN) {
return (
<>
<BlueSpacing20 />
<Text style={[styles.advancedText, stylesHook.advancedText]}>{loc.settings.advanced_options}</Text>
<BlueSpacing20 />
<BlueText>{loc.wallets.add_lndhub}</BlueText>
<View style={[styles.lndUri, stylesHook.lndUri]}>
<TextInput
value={walletBaseURI}
onChangeText={setWalletBaseURI}
onSubmitEditing={Keyboard.dismiss}
placeholder={loc.wallets.add_lndhub_placeholder}
clearButtonMode="while-editing"
autoCapitalize="none"
textContentType="URL"
autoCorrect={false}
placeholderTextColor="#81868e"
style={styles.textInputCommon}
editable={!isLoading}
underlineColorAndroid="transparent"
/> />
</View> </View>
); </>
} else if (selectedWalletType === ButtonSelected.OFFCHAIN) { );
return ( }
<> })()}
<BlueSpacing20 /> {isAdvancedModeEnabled === true && selectedWalletType === ButtonSelected.ONCHAIN && !isLoading && (
<Text style={[styles.advancedText, stylesHook.advancedText]}>{loc.settings.advanced_options}</Text> <BlueButtonLink style={styles.import} title={entropyButtonText} onPress={navigateToEntropy} />
<BlueSpacing20 /> )}
<BlueText>{loc.wallets.add_lndhub}</BlueText> <BlueSpacing20 />
<View style={[styles.lndUri, stylesHook.lndUri]}> {!isLoading ? (
<TextInput <>
value={walletBaseURI} <Button
onChangeText={setWalletBaseURI} testID="Create"
onSubmitEditing={Keyboard.dismiss} title={loc.wallets.add_create}
placeholder={loc.wallets.add_lndhub_placeholder} disabled={
clearButtonMode="while-editing" !selectedWalletType || (selectedWalletType === ButtonSelected.OFFCHAIN && (walletBaseURI ?? '').trim().length === 0)
autoCapitalize="none" }
textContentType="URL" onPress={createWallet}
autoCorrect={false} />
placeholderTextColor="#81868e"
style={styles.textInputCommon}
editable={!isLoading}
underlineColorAndroid="transparent"
/>
</View>
</>
);
}
})()}
{isAdvancedModeEnabled === true && selectedWalletType === ButtonSelected.ONCHAIN && !isLoading && (
<BlueButtonLink style={styles.import} title={entropyButtonText} onPress={navigateToEntropy} />
)}
<BlueSpacing20 />
{!isLoading ? (
<>
<Button
testID="Create"
title={loc.wallets.add_create}
disabled={
!selectedWalletType || (selectedWalletType === ButtonSelected.OFFCHAIN && (walletBaseURI ?? '').trim().length === 0)
}
onPress={createWallet}
/>
<BlueButtonLink <BlueButtonLink
testID="ImportWallet" testID="ImportWallet"
style={styles.import} style={styles.import}
title={loc.wallets.add_import_wallet} title={loc.wallets.add_import_wallet}
onPress={navigateToImportWallet} onPress={navigateToImportWallet}
/> />
<BlueSpacing40 /> <BlueSpacing40 />
</> </>
) : ( ) : (
<ActivityIndicator /> <ActivityIndicator />
)} )}
</View> </View>
</KeyboardAvoidingView>
</ScrollView> </ScrollView>
); );
}; };

View file

@ -7,7 +7,6 @@ import {
FlatList, FlatList,
InteractionManager, InteractionManager,
Keyboard, Keyboard,
KeyboardAvoidingView,
LayoutAnimation, LayoutAnimation,
ListRenderItemInfo, ListRenderItemInfo,
Platform, Platform,
@ -17,7 +16,7 @@ import {
View, View,
} from 'react-native'; } from 'react-native';
import { Badge, Icon } from '@rneui/themed'; import { Badge, Icon } from '@rneui/themed';
import { isDesktop, isTablet } from '../../blue_modules/environment'; import { isDesktop } from '../../blue_modules/environment';
import { encodeUR } from '../../blue_modules/ur'; import { encodeUR } from '../../blue_modules/ur';
import { import {
BlueButtonLink, BlueButtonLink,
@ -631,23 +630,19 @@ const ViewEditMultisigCosigners: React.FC = () => {
return ( return (
<View style={[styles.root, stylesHook.root]} ref={discardChangesRef}> <View style={[styles.root, stylesHook.root]} ref={discardChangesRef}>
<KeyboardAvoidingView <FlatList
enabled={!isTablet} ListHeaderComponent={tipKeys}
behavior={Platform.OS === 'ios' ? 'padding' : undefined} data={data.current}
keyboardVerticalOffset={62} extraData={vaultKeyData}
style={[styles.mainBlock, styles.root]} renderItem={_renderKeyItem}
> automaticallyAdjustKeyboardInsets
<FlatList contentInsetAdjustmentBehavior="automatic"
ListHeaderComponent={tipKeys} automaticallyAdjustContentInsets
data={data.current} keyExtractor={(_item, index) => `${index}`}
extraData={vaultKeyData} />
renderItem={_renderKeyItem} <BlueSpacing10 />
keyExtractor={(_item, index) => `${index}`} {footer}
/> <BlueSpacing40 />
<BlueSpacing10 />
{footer}
<BlueSpacing40 />
</KeyboardAvoidingView>
{renderProvideMnemonicsModal()} {renderProvideMnemonicsModal()}
@ -689,7 +684,6 @@ const styles = StyleSheet.create({
marginBottom: 32, marginBottom: 32,
}, },
headerText: { fontSize: 15, color: '#13244D' }, headerText: { fontSize: 15, color: '#13244D' },
mainBlock: { marginHorizontal: 16 },
alignItemsCenter: { alignItems: 'center', justifyContent: 'space-between' }, alignItemsCenter: { alignItems: 'center', justifyContent: 'space-between' },
shareModalHeight: { minHeight: 450 }, shareModalHeight: { minHeight: 450 },
tipKeys: { tipKeys: {

View file

@ -5,8 +5,6 @@ import {
I18nManager, I18nManager,
InteractionManager, InteractionManager,
Keyboard, Keyboard,
KeyboardAvoidingView,
Platform,
ScrollView, ScrollView,
StyleSheet, StyleSheet,
Switch, Switch,
@ -419,6 +417,7 @@ const WalletDetails = () => {
return ( return (
<ScrollView <ScrollView
automaticallyAdjustKeyboardInsets
contentInsetAdjustmentBehavior="automatic" contentInsetAdjustmentBehavior="automatic"
centerContent={isLoading} centerContent={isLoading}
contentContainerStyle={styles.scrollViewContent} contentContainerStyle={styles.scrollViewContent}
@ -453,21 +452,19 @@ const WalletDetails = () => {
} }
})()} })()}
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.add_wallet_name.toLowerCase()}</Text> <Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.add_wallet_name.toLowerCase()}</Text>
<KeyboardAvoidingView enabled={!Platform.isPad} behavior={Platform.OS === 'ios' ? 'position' : null}> <View style={[styles.input, stylesHook.input]}>
<View style={[styles.input, stylesHook.input]}> <TextInput
<TextInput value={walletName}
value={walletName} onChangeText={setWalletName}
onChangeText={setWalletName} onBlur={walletNameTextInputOnBlur}
onBlur={walletNameTextInputOnBlur} numberOfLines={1}
numberOfLines={1} placeholderTextColor="#81868e"
placeholderTextColor="#81868e" style={styles.inputText}
style={styles.inputText} editable={!isLoading}
editable={!isLoading} underlineColorAndroid="transparent"
underlineColorAndroid="transparent" testID="WalletNameInput"
testID="WalletNameInput" />
/> </View>
</View>
</KeyboardAvoidingView>
<BlueSpacing20 /> <BlueSpacing20 />
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_type.toLowerCase()}</Text> <Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_type.toLowerCase()}</Text>
<Text style={[styles.textValue, stylesHook.textValue]}>{wallet.typeReadable}</Text> <Text style={[styles.textValue, stylesHook.textValue]}>{wallet.typeReadable}</Text>

View file

@ -1,12 +1,11 @@
import { useTheme } from '@react-navigation/native'; import { useTheme } from '@react-navigation/native';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Keyboard, KeyboardAvoidingView, Platform, StyleSheet, TextInput, View } from 'react-native'; import { Keyboard, ScrollView, StyleSheet, TextInput, View } from 'react-native';
import { generateChecksumWords } from '../../blue_modules/checksumWords'; import { generateChecksumWords } from '../../blue_modules/checksumWords';
import { BlueCard, BlueSpacing10, BlueSpacing20, BlueText } from '../../BlueComponents'; import { BlueCard, BlueSpacing10, BlueSpacing20, BlueText } from '../../BlueComponents';
import { randomBytes } from '../../class/rng'; import { randomBytes } from '../../class/rng';
import Button from '../../components/Button'; import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea';
import loc from '../../loc'; import loc from '../../loc';
const GenerateWord = () => { const GenerateWord = () => {
@ -53,51 +52,51 @@ const GenerateWord = () => {
}; };
return ( return (
<SafeArea style={styles.blueArea}> <ScrollView
<KeyboardAvoidingView style={styles.blueArea}
enabled={!Platform.isPad} keyboardShouldPersistTaps="handled"
behavior={Platform.OS === 'ios' ? 'position' : null} automaticallyAdjustContentInsets
keyboardShouldPersistTaps="handled" automaticallyAdjustKeyboardInsets
> contentInsetAdjustmentBehavior="automatic"
<View style={styles.wrapper}> >
<BlueCard style={styles.mainCard}> <View style={styles.wrapper}>
<View style={[styles.input, stylesHooks.input]}> <BlueCard style={styles.mainCard}>
<TextInput <View style={[styles.input, stylesHooks.input]}>
style={styles.text} <TextInput
maxHeight={100} style={styles.text}
minHeight={100} maxHeight={100}
maxWidth="100%" minHeight={100}
minWidth="100%" maxWidth="100%"
multiline minWidth="100%"
editable multiline
placeholder={loc.autofill_word.enter} editable
placeholderTextColor="#81868e" placeholder={loc.autofill_word.enter}
value={mnemonic} placeholderTextColor="#81868e"
onChangeText={handleUpdateMnemonic} value={mnemonic}
testID="MnemonicInput" onChangeText={handleUpdateMnemonic}
/> testID="MnemonicInput"
</View> />
</View>
<BlueSpacing10 /> <BlueSpacing10 />
<Button title={loc.send.input_clear} onPress={clearMnemonicInput} /> <Button title={loc.send.input_clear} onPress={clearMnemonicInput} />
<BlueSpacing20 /> <BlueSpacing20 />
<BlueText style={styles.center} testID="Result"> <BlueText style={styles.center} testID="Result">
{result} {result}
</BlueText> </BlueText>
<BlueSpacing20 /> <BlueSpacing20 />
<View> <View>
<Button <Button
disabled={mnemonic.trim().length === 0} disabled={mnemonic.trim().length === 0}
title={loc.autofill_word.generate_word} title={loc.autofill_word.generate_word}
onPress={checkMnemonic} onPress={checkMnemonic}
testID="GenerateWord" testID="GenerateWord"
/> />
</View> </View>
<BlueSpacing20 /> <BlueSpacing20 />
</BlueCard> </BlueCard>
</View> </View>
</KeyboardAvoidingView> </ScrollView>
</SafeArea>
); );
}; };

View file

@ -1,23 +1,12 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useRoute } from '@react-navigation/native'; import { useRoute } from '@react-navigation/native';
import { import { ActivityIndicator, Keyboard, LayoutAnimation, Platform, ScrollView, StyleSheet, TextInput, View } from 'react-native';
ActivityIndicator,
Keyboard,
KeyboardAvoidingView,
LayoutAnimation,
Platform,
StyleSheet,
TextInput,
TouchableWithoutFeedback,
View,
} from 'react-native';
import { Icon } from '@rneui/themed'; import { Icon } from '@rneui/themed';
import Share from 'react-native-share'; import Share from 'react-native-share';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueDoneAndDismissKeyboardInputAccessory, BlueFormLabel, BlueSpacing10, BlueSpacing20, BlueSpacing40 } from '../../BlueComponents'; import { BlueDoneAndDismissKeyboardInputAccessory, BlueFormLabel, BlueSpacing10, BlueSpacing20, BlueSpacing40 } from '../../BlueComponents';
import presentAlert from '../../components/Alert'; import presentAlert from '../../components/Alert';
import { FButton, FContainer } from '../../components/FloatButtons'; import { FButton, FContainer } from '../../components/FloatButtons';
import SafeArea from '../../components/SafeArea';
import { useTheme } from '../../components/themes'; import { useTheme } from '../../components/themes';
import loc from '../../loc'; import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage'; import { useStorage } from '../../hooks/context/useStorage';
@ -116,122 +105,124 @@ const SignVerify = () => {
); );
return ( return (
<SafeArea style={[styles.root, stylesHooks.root]}> <ScrollView
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}> automaticallyAdjustContentInsets
<KeyboardAvoidingView style={[styles.root, stylesHooks.root]}> automaticallyAdjustKeyboardInsets
{!isKeyboardVisible && ( contentInsetAdjustmentBehavior="automatic"
<> contentContainerStyle={styles.root}
<BlueSpacing20 /> style={[styles.root, stylesHooks.root]}
<BlueFormLabel>{loc.addresses.sign_help}</BlueFormLabel> >
<BlueSpacing20 /> {!isKeyboardVisible && (
</> <>
)} <BlueSpacing20 />
<BlueFormLabel>{loc.addresses.sign_help}</BlueFormLabel>
<BlueSpacing20 />
</>
)}
<TextInput <TextInput
multiline multiline
textAlignVertical="top" textAlignVertical="top"
blurOnSubmit blurOnSubmit
placeholder={loc.addresses.sign_placeholder_address} placeholder={loc.addresses.sign_placeholder_address}
placeholderTextColor="#81868e" placeholderTextColor="#81868e"
value={address} value={address}
onChangeText={t => setAddress(t.replace('\n', ''))} onChangeText={t => setAddress(t.replace('\n', ''))}
testID="Signature" testID="Signature"
style={[styles.text, stylesHooks.text]} style={[styles.text, stylesHooks.text]}
autoCorrect={false} autoCorrect={false}
autoCapitalize="none" autoCapitalize="none"
spellCheck={false} spellCheck={false}
editable={!loading} editable={!loading}
/> />
<BlueSpacing10 />
<TextInput
multiline
textAlignVertical="top"
blurOnSubmit
placeholder={loc.addresses.sign_placeholder_signature}
placeholderTextColor="#81868e"
value={signature}
onChangeText={t => setSignature(t.replace('\n', ''))}
testID="Signature"
style={[styles.text, stylesHooks.text]}
autoCorrect={false}
autoCapitalize="none"
spellCheck={false}
editable={!loading}
/>
<BlueSpacing10 />
<TextInput
multiline
placeholder={loc.addresses.sign_placeholder_message}
placeholderTextColor="#81868e"
value={message}
onChangeText={setMessage}
testID="Message"
inputAccessoryViewID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}
style={[styles.flex, styles.text, styles.textMessage, stylesHooks.text]}
autoCorrect={false}
autoCapitalize="none"
spellCheck={false}
editable={!loading}
onFocus={() => handleFocus(true)}
onBlur={() => handleFocus(false)}
/>
<BlueSpacing40 />
{isShareVisible && !isKeyboardVisible && (
<>
<FContainer inline>
<FButton
onPress={handleShare}
text={loc.multisig.share}
icon={
<View style={styles.buttonsIcon}>
<Icon name="external-link" size={16} type="font-awesome" color={colors.buttonAlternativeTextColor} />
</View>
}
/>
</FContainer>
<BlueSpacing10 /> <BlueSpacing10 />
</>
)}
<TextInput {!isKeyboardVisible && (
multiline <>
textAlignVertical="top" <FContainer inline>
blurOnSubmit <FButton onPress={handleSign} text={loc.addresses.sign_sign} disabled={loading} />
placeholder={loc.addresses.sign_placeholder_signature} <FButton onPress={handleVerify} text={loc.addresses.sign_verify} disabled={loading} />
placeholderTextColor="#81868e" </FContainer>
value={signature}
onChangeText={t => setSignature(t.replace('\n', ''))}
testID="Signature"
style={[styles.text, stylesHooks.text]}
autoCorrect={false}
autoCapitalize="none"
spellCheck={false}
editable={!loading}
/>
<BlueSpacing10 /> <BlueSpacing10 />
</>
)}
<TextInput {Platform.select({
multiline ios: (
placeholder={loc.addresses.sign_placeholder_message} <BlueDoneAndDismissKeyboardInputAccessory
placeholderTextColor="#81868e" onClearTapped={() => setMessage('')}
value={message} onPasteTapped={text => {
onChangeText={setMessage} setMessage(text);
testID="Message" Keyboard.dismiss();
inputAccessoryViewID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID} }}
style={[styles.flex, styles.text, styles.textMessage, stylesHooks.text]}
autoCorrect={false}
autoCapitalize="none"
spellCheck={false}
editable={!loading}
onFocus={() => handleFocus(true)}
onBlur={() => handleFocus(false)}
/> />
<BlueSpacing40 /> ),
android: isToolbarVisibleForAndroid && (
{isShareVisible && !isKeyboardVisible && ( <BlueDoneAndDismissKeyboardInputAccessory
<> onClearTapped={() => {
<FContainer inline> setMessage('');
<FButton Keyboard.dismiss();
onPress={handleShare} }}
text={loc.multisig.share} onPasteTapped={text => {
icon={ setMessage(text);
<View style={styles.buttonsIcon}> Keyboard.dismiss();
<Icon name="external-link" size={16} type="font-awesome" color={colors.buttonAlternativeTextColor} /> }}
</View> />
} ),
/> })}
</FContainer> </ScrollView>
<BlueSpacing10 />
</>
)}
{!isKeyboardVisible && (
<>
<FContainer inline>
<FButton onPress={handleSign} text={loc.addresses.sign_sign} disabled={loading} />
<FButton onPress={handleVerify} text={loc.addresses.sign_verify} disabled={loading} />
</FContainer>
<BlueSpacing10 />
</>
)}
{Platform.select({
ios: (
<BlueDoneAndDismissKeyboardInputAccessory
onClearTapped={() => setMessage('')}
onPasteTapped={text => {
setMessage(text);
Keyboard.dismiss();
}}
/>
),
android: isToolbarVisibleForAndroid && (
<BlueDoneAndDismissKeyboardInputAccessory
onClearTapped={() => {
setMessage('');
Keyboard.dismiss();
}}
onPasteTapped={text => {
setMessage(text);
Keyboard.dismiss();
}}
/>
),
})}
</KeyboardAvoidingView>
</TouchableWithoutFeedback>
</SafeArea>
); );
}; };