/* eslint react/prop-types: "off", react-native/no-inline-styles: "off" */
import React, { Component, forwardRef } from 'react';
import PropTypes from 'prop-types';
import { Icon, Text, Header, ListItem, Avatar } from 'react-native-elements';
import {
ActivityIndicator,
Alert,
Animated,
Dimensions,
Image,
InputAccessoryView,
Keyboard,
KeyboardAvoidingView,
Platform,
SafeAreaView,
StyleSheet,
Switch,
TextInput,
TouchableOpacity,
View,
I18nManager,
ImageBackground,
} from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
import NetworkTransactionFees, { NetworkTransactionFee, NetworkTransactionFeeType } from './models/networkTransactionFees';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useTheme } from '@react-navigation/native';
import { BlueCurrentTheme } from './components/themes';
import PlusIcon from './components/icons/PlusIcon';
import loc, { formatStringAddTwoWhiteSpaces } from './loc';
const { height, width } = Dimensions.get('window');
const aspectRatio = height / width;
let isIpad;
if (aspectRatio > 1.6) {
isIpad = false;
} else {
isIpad = true;
}
export const BlueButton = props => {
const { colors } = useTheme();
let backgroundColor = props.backgroundColor ? props.backgroundColor : colors.mainColor || BlueCurrentTheme.colors.mainColor;
let fontColor = props.buttonTextColor || colors.buttonTextColor;
if (props.disabled === true) {
backgroundColor = colors.buttonDisabledBackgroundColor;
fontColor = colors.buttonDisabledTextColor;
}
return (
{props.icon && }
{props.title && {props.title}}
);
};
export const SecondButton = forwardRef((props, ref) => {
const { colors } = useTheme();
let backgroundColor = props.backgroundColor ? props.backgroundColor : colors.buttonBlueBackgroundColor;
let fontColor = colors.buttonTextColor;
if (props.disabled === true) {
backgroundColor = colors.buttonDisabledBackgroundColor;
fontColor = colors.buttonDisabledTextColor;
}
return (
{props.icon && }
{props.title && {props.title}}
);
});
export const BitcoinButton = props => {
const { colors } = useTheme();
return (
{loc.wallets.add_bitcoin}
{loc.wallets.add_bitcoin_explain}
);
};
export const VaultButton = props => {
const { colors } = useTheme();
return (
{loc.multisig.multisig_vault}
{loc.multisig.multisig_vault_explain}
);
};
export const LightningButton = props => {
const { colors } = useTheme();
return (
{loc.wallets.add_lightning}
{loc.wallets.add_lightning_explain}
);
};
/**
* TODO: remove this comment once this file gets properly converted to typescript.
*
* @type {React.FC}
*/
export const BlueButtonLink = forwardRef((props, ref) => {
const { colors } = useTheme();
return (
{props.title}
);
});
export const BlueAlertWalletExportReminder = ({ onSuccess = () => {}, onFailure }) => {
Alert.alert(
loc.wallets.details_title,
loc.pleasebackup.ask,
[
{ text: loc.pleasebackup.ask_yes, onPress: onSuccess, style: 'cancel' },
{ text: loc.pleasebackup.ask_no, onPress: onFailure },
],
{ cancelable: false },
);
};
export const BluePrivateBalance = () => {
return (
);
};
export const BlueCopyToClipboardButton = ({ stringToCopy, displayText = false }) => {
return (
Clipboard.setString(stringToCopy)}>
{displayText || loc.transactions.details_copy}
);
};
export class BlueCopyTextToClipboard extends Component {
static propTypes = {
text: PropTypes.string,
truncated: PropTypes.bool,
};
static defaultProps = {
text: '',
truncated: false,
};
constructor(props) {
super(props);
this.state = { hasTappedText: false, address: props.text };
}
static getDerivedStateFromProps(props, state) {
if (state.hasTappedText) {
return { hasTappedText: state.hasTappedText, address: state.address, truncated: props.truncated };
} else {
return { hasTappedText: state.hasTappedText, address: props.text, truncated: props.truncated };
}
}
copyToClipboard = () => {
this.setState({ hasTappedText: true }, () => {
Clipboard.setString(this.props.text);
this.setState({ address: loc.wallets.xpub_copiedToClipboard }, () => {
setTimeout(() => {
this.setState({ hasTappedText: false, address: this.props.text });
}, 1000);
});
});
};
render() {
return (
{this.state.address}
);
}
}
const styleCopyTextToClipboard = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
export const SafeBlueArea = props => {
const { style, ...nonStyleProps } = props;
const { colors } = useTheme();
const baseStyle = { flex: 1, backgroundColor: colors.background };
return ;
};
export const BlueCard = props => {
return ;
};
export const BlueText = props => {
const { colors } = useTheme();
const style = StyleSheet.compose({ color: colors.foregroundColor, writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr' }, props.style);
return ;
};
export const BlueTextCentered = props => {
const { colors } = useTheme();
return ;
};
export const BlueListItem = React.memo(props => {
const { colors } = useTheme();
return (
{props.leftAvatar && {props.leftAvatar}}
{props.leftIcon && }
{props.title}
{props.subtitle && (
{props.subtitle}
)}
{props.rightTitle && (
{props.rightTitle}
)}
{props.isLoading ? (
) : (
<>
{props.chevron && }
{props.rightIcon && }
{props.switch && }
{props.checkmark && }
>
)}
);
});
export const BlueFormLabel = props => {
const { colors } = useTheme();
return (
);
};
export const BlueFormMultiInput = props => {
const { colors } = useTheme();
return (
);
};
export const BlueHeaderDefaultSub = props => {
const { colors } = useTheme();
return (
{props.leftText}
}
{...props}
/>
);
};
export const BlueHeaderDefaultMain = props => {
const { colors } = useTheme();
const { isDrawerList } = props;
return (
{props.leftText}
);
};
export const BlueSpacing = props => {
return ;
};
export const BlueSpacing40 = props => {
return ;
};
export class is {
static ipad() {
return isIpad;
}
}
export const BlueSpacing20 = props => {
const { horizontal = false } = props;
return ;
};
export const BlueSpacing10 = props => {
return ;
};
export const BlueDismissKeyboardInputAccessory = () => {
const { colors } = useTheme();
BlueDismissKeyboardInputAccessory.InputAccessoryViewID = 'BlueDismissKeyboardInputAccessory';
return Platform.OS !== 'ios' ? null : (
);
};
export const BlueDoneAndDismissKeyboardInputAccessory = props => {
const { colors } = useTheme();
BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID = 'BlueDoneAndDismissKeyboardInputAccessory';
const onPasteTapped = async () => {
const clipboard = await Clipboard.getString();
props.onPasteTapped(clipboard);
};
const inputView = (
);
if (Platform.OS === 'ios') {
return {inputView};
} else {
return {inputView};
}
};
export const BlueLoading = props => {
return (
);
};
export class BlueReplaceFeeSuggestions extends Component {
static propTypes = {
onFeeSelected: PropTypes.func.isRequired,
transactionMinimum: PropTypes.number.isRequired,
};
static defaultProps = {
transactionMinimum: 1,
};
state = {
customFeeValue: '1',
};
async componentDidMount() {
try {
const cachedNetworkTransactionFees = JSON.parse(await AsyncStorage.getItem(NetworkTransactionFee.StorageKey));
if (cachedNetworkTransactionFees && 'fastestFee' in cachedNetworkTransactionFees) {
this.setState({ networkFees: cachedNetworkTransactionFees }, () => this.onFeeSelected(NetworkTransactionFeeType.FAST));
}
} catch (_) {}
const networkFees = await NetworkTransactionFees.recommendedFees();
this.setState({ networkFees }, () => this.onFeeSelected(NetworkTransactionFeeType.FAST));
}
onFeeSelected = selectedFeeType => {
if (selectedFeeType !== NetworkTransactionFeeType.CUSTOM) {
Keyboard.dismiss();
}
if (selectedFeeType === NetworkTransactionFeeType.FAST) {
this.props.onFeeSelected(this.state.networkFees.fastestFee);
this.setState({ selectedFeeType }, () => this.props.onFeeSelected(this.state.networkFees.fastestFee));
} else if (selectedFeeType === NetworkTransactionFeeType.MEDIUM) {
this.setState({ selectedFeeType }, () => this.props.onFeeSelected(this.state.networkFees.mediumFee));
} else if (selectedFeeType === NetworkTransactionFeeType.SLOW) {
this.setState({ selectedFeeType }, () => this.props.onFeeSelected(this.state.networkFees.slowFee));
} else if (selectedFeeType === NetworkTransactionFeeType.CUSTOM) {
this.props.onFeeSelected(Number(this.state.customFeeValue));
}
};
onCustomFeeTextChange = customFee => {
const customFeeValue = customFee.replace(/[^0-9]/g, '');
this.setState({ customFeeValue, selectedFeeType: NetworkTransactionFeeType.CUSTOM }, () => {
this.onFeeSelected(NetworkTransactionFeeType.CUSTOM);
});
};
render() {
const { networkFees, selectedFeeType } = this.state;
return (
{networkFees &&
[
{
label: loc.send.fee_fast,
time: loc.send.fee_10m,
type: NetworkTransactionFeeType.FAST,
rate: networkFees.fastestFee,
active: selectedFeeType === NetworkTransactionFeeType.FAST,
},
{
label: formatStringAddTwoWhiteSpaces(loc.send.fee_medium),
time: loc.send.fee_3h,
type: NetworkTransactionFeeType.MEDIUM,
rate: networkFees.mediumFee,
active: selectedFeeType === NetworkTransactionFeeType.MEDIUM,
},
{
label: loc.send.fee_slow,
time: loc.send.fee_1d,
type: NetworkTransactionFeeType.SLOW,
rate: networkFees.slowFee,
active: selectedFeeType === NetworkTransactionFeeType.SLOW,
},
].map(({ label, type, time, rate, active }, index) => (
this.onFeeSelected(type)}
style={[
{ paddingHorizontal: 16, paddingVertical: 8, marginBottom: 10 },
active && { borderRadius: 8, backgroundColor: BlueCurrentTheme.colors.incomingBackgroundColor },
]}
>
{label}
~{time}
{rate} sat/byte
))}
this.customTextInput.focus()}
style={[
{ paddingHorizontal: 16, paddingVertical: 8, marginBottom: 10 },
selectedFeeType === NetworkTransactionFeeType.CUSTOM && {
borderRadius: 8,
backgroundColor: BlueCurrentTheme.colors.incomingBackgroundColor,
},
]}
>
{formatStringAddTwoWhiteSpaces(loc.send.fee_custom)}
(this.customTextInput = ref)}
maxLength={9}
style={{
backgroundColor: BlueCurrentTheme.colors.inputBackgroundColor,
borderBottomColor: BlueCurrentTheme.colors.formBorder,
borderBottomWidth: 0.5,
borderColor: BlueCurrentTheme.colors.formBorder,
borderRadius: 4,
borderWidth: 1.0,
color: '#81868e',
flex: 1,
marginRight: 10,
minHeight: 33,
paddingRight: 5,
paddingLeft: 5,
}}
onFocus={() => this.onCustomFeeTextChange(this.state.customFeeValue)}
defaultValue={`${this.props.transactionMinimum}`}
placeholder={loc.send.fee_satvbyte}
placeholderTextColor="#81868e"
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
/>
sat/byte
{loc.formatString(loc.send.fee_replace_minvb, { min: this.props.transactionMinimum })}
);
}
}
export function BlueBigCheckmark({ style }) {
const defaultStyles = {
backgroundColor: '#ccddf9',
width: 120,
height: 120,
borderRadius: 60,
alignSelf: 'center',
justifyContent: 'center',
marginTop: 0,
marginBottom: 0,
};
const mergedStyles = { ...defaultStyles, ...style };
return (
);
}
const tabsStyles = StyleSheet.create({
root: {
flexDirection: 'row',
height: 50,
borderColor: '#e3e3e3',
borderBottomWidth: 1,
},
tabRoot: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
borderColor: 'white',
borderBottomWidth: 2,
},
});
export const BlueTabs = ({ active, onSwitch, tabs }) => (
{tabs.map((Tab, i) => (
onSwitch(i)}
style={[
tabsStyles.tabRoot,
active === i && {
borderColor: BlueCurrentTheme.colors.buttonAlternativeTextColor,
borderBottomWidth: 2,
},
]}
>
))}
);