Merge branch 'master' into limpbrains-test-walletdetails

This commit is contained in:
Ivan Vershigora 2021-03-04 10:12:42 +03:00
commit daf8cf5b9a
32 changed files with 1623 additions and 1680 deletions

View file

@ -7,7 +7,6 @@ import {
Alert,
Animated,
Dimensions,
findNodeHandle,
Image,
InputAccessoryView,
Keyboard,
@ -24,7 +23,7 @@ import {
TouchableWithoutFeedback,
View,
} from 'react-native';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import LinearGradient from 'react-native-linear-gradient';
import { LightningCustodianWallet, MultisigHDWallet } from './class';
import { BitcoinUnit } from './models/bitcoinUnits';
@ -33,13 +32,12 @@ import WalletGradient from './class/wallet-gradient';
import { BlurView } from '@react-native-community/blur';
import NetworkTransactionFees, { NetworkTransactionFee, NetworkTransactionFeeType } from './models/networkTransactionFees';
import Biometric from './class/biometrics';
import { getSystemName } from 'react-native-device-info';
import { encodeUR } from 'bc-ur/dist';
import QRCode from 'react-native-qrcode-svg';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation, useTheme } from '@react-navigation/native';
import { BlueCurrentTheme } from './components/themes';
import loc, { formatBalance, formatBalanceWithoutSuffix, formatBalancePlain, removeTrailingZeros, transactionTimeToReadable } from './loc';
import loc, { formatBalance, formatBalanceWithoutSuffix, transactionTimeToReadable } from './loc';
import Lnurl from './class/lnurl';
import { BlueStorageContext } from './blue_modules/storage-context';
import ToolTipMenu from './components/TooltipMenu';
@ -47,9 +45,6 @@ import ToolTipMenu from './components/TooltipMenu';
/** @type {AppStorage} */
const { height, width } = Dimensions.get('window');
const aspectRatio = height / width;
const BigNumber = require('bignumber.js');
const currency = require('./blue_modules/currency');
const fs = require('./blue_modules/fs');
let isIpad;
if (aspectRatio > 1.6) {
isIpad = false;
@ -1558,92 +1553,6 @@ export const BlueTransactionListItem = React.memo(({ item, itemPriceUnit = Bitco
);
});
const isDesktop = getSystemName() === 'Mac OS X';
export const BlueAddressInput = ({
isLoading = false,
address = '',
placeholder = loc.send.details_address,
onChangeText,
onBarScanned,
launchedBy,
}) => {
const { colors } = useTheme();
const scanButtonRef = useRef();
return (
<View
style={{
flexDirection: 'row',
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
borderWidth: 1.0,
borderBottomWidth: 0.5,
backgroundColor: colors.inputBackgroundColor,
minHeight: 44,
height: 44,
marginHorizontal: 20,
alignItems: 'center',
marginVertical: 8,
borderRadius: 4,
}}
>
<TextInput
testID="AddressInput"
onChangeText={onChangeText}
placeholder={placeholder}
numberOfLines={1}
placeholderTextColor="#81868e"
value={address}
style={{ flex: 1, marginHorizontal: 8, minHeight: 33, color: '#81868e' }}
editable={!isLoading}
onSubmitEditing={Keyboard.dismiss}
/>
<TouchableOpacity
testID="BlueAddressInputScanQrButton"
disabled={isLoading}
ref={scanButtonRef}
onPress={() => {
Keyboard.dismiss();
if (isDesktop) {
fs.showActionSheet({ anchor: findNodeHandle(scanButtonRef.current) }).then(onBarScanned);
} else {
NavigationService.navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
params: {
launchedBy,
onBarScanned,
},
});
}
}}
style={{
height: 36,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: colors.scanLabel,
borderRadius: 4,
paddingVertical: 4,
paddingHorizontal: 8,
marginHorizontal: 4,
}}
>
<Image style={{}} source={require('./img/scan-white.png')} />
<Text style={{ marginLeft: 4, color: colors.inverseForegroundColor }}>{loc.send.details_scan}</Text>
</TouchableOpacity>
</View>
);
};
BlueAddressInput.propTypes = {
isLoading: PropTypes.bool,
onChangeText: PropTypes.func,
onBarScanned: PropTypes.func.isRequired,
launchedBy: PropTypes.string.isRequired,
address: PropTypes.string,
placeholder: PropTypes.string,
};
export class BlueReplaceFeeSuggestions extends Component {
static propTypes = {
onFeeSelected: PropTypes.func.isRequired,
@ -1799,272 +1708,6 @@ export class BlueReplaceFeeSuggestions extends Component {
}
}
export class BlueBitcoinAmount extends Component {
static propTypes = {
isLoading: PropTypes.bool,
/**
* amount is a sting thats always in current unit denomination, e.g. '0.001' or '9.43' or '10000'
*/
amount: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
* callback that returns currently typed amount, in current denomination, e.g. 0.001 or 10000 or $9.34
* (btc, sat, fiat)
*/
onChangeText: PropTypes.func,
/**
* callback thats fired to notify of currently selected denomination, returns <BitcoinUnit.*>
*/
onAmountUnitChange: PropTypes.func,
disabled: PropTypes.bool,
};
/**
* cache of conversions fiat amount => satoshi
* @type {{}}
*/
static conversionCache = {};
static getCachedSatoshis(amount) {
return BlueBitcoinAmount.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY] || false;
}
static setCachedSatoshis(amount, sats) {
BlueBitcoinAmount.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY] = sats;
}
constructor(props) {
super(props);
this.state = { unit: props.unit || BitcoinUnit.BTC, previousUnit: BitcoinUnit.SATS };
}
/**
* here we must recalculate old amont value (which was denominated in `previousUnit`) to new denomination `newUnit`
* and fill this value in input box, so user can switch between, for example, 0.001 BTC <=> 100000 sats
*
* @param previousUnit {string} one of {BitcoinUnit.*}
* @param newUnit {string} one of {BitcoinUnit.*}
*/
onAmountUnitChange(previousUnit, newUnit) {
const amount = this.props.amount || 0;
console.log('was:', amount, previousUnit, '; converting to', newUnit);
let sats = 0;
switch (previousUnit) {
case BitcoinUnit.BTC:
sats = new BigNumber(amount).multipliedBy(100000000).toString();
break;
case BitcoinUnit.SATS:
sats = amount;
break;
case BitcoinUnit.LOCAL_CURRENCY:
sats = new BigNumber(currency.fiatToBTC(amount)).multipliedBy(100000000).toString();
break;
}
if (previousUnit === BitcoinUnit.LOCAL_CURRENCY && BlueBitcoinAmount.conversionCache[amount + previousUnit]) {
// cache hit! we reuse old value that supposedly doesnt have rounding errors
sats = BlueBitcoinAmount.conversionCache[amount + previousUnit];
}
console.log('so, in sats its', sats);
const newInputValue = formatBalancePlain(sats, newUnit, false);
console.log('and in', newUnit, 'its', newInputValue);
if (newUnit === BitcoinUnit.LOCAL_CURRENCY && previousUnit === BitcoinUnit.SATS) {
// we cache conversion, so when we will need reverse conversion there wont be a rounding error
BlueBitcoinAmount.conversionCache[newInputValue + newUnit] = amount;
}
this.props.onChangeText(newInputValue);
if (this.props.onAmountUnitChange) this.props.onAmountUnitChange(newUnit);
}
/**
* responsible for cycling currently selected denomination, BTC->SAT->LOCAL_CURRENCY->BTC
*/
changeAmountUnit = () => {
let previousUnit = this.state.unit;
let newUnit;
if (previousUnit === BitcoinUnit.BTC) {
newUnit = BitcoinUnit.SATS;
} else if (previousUnit === BitcoinUnit.SATS) {
newUnit = BitcoinUnit.LOCAL_CURRENCY;
} else if (previousUnit === BitcoinUnit.LOCAL_CURRENCY) {
newUnit = BitcoinUnit.BTC;
} else {
newUnit = BitcoinUnit.BTC;
previousUnit = BitcoinUnit.SATS;
}
this.setState({ unit: newUnit, previousUnit }, () => this.onAmountUnitChange(previousUnit, newUnit));
};
maxLength = () => {
switch (this.state.unit) {
case BitcoinUnit.BTC:
return 10;
case BitcoinUnit.SATS:
return 15;
default:
return 15;
}
};
textInput = React.createRef();
handleTextInputOnPress = () => {
this.textInput.current.focus();
};
render() {
const amount = this.props.amount || 0;
let secondaryDisplayCurrency = formatBalanceWithoutSuffix(amount, BitcoinUnit.LOCAL_CURRENCY, false);
// if main display is sat or btc - secondary display is fiat
// if main display is fiat - secondary dislay is btc
let sat;
switch (this.state.unit) {
case BitcoinUnit.BTC:
sat = new BigNumber(amount).multipliedBy(100000000).toString();
secondaryDisplayCurrency = formatBalanceWithoutSuffix(sat, BitcoinUnit.LOCAL_CURRENCY, false);
break;
case BitcoinUnit.SATS:
secondaryDisplayCurrency = formatBalanceWithoutSuffix((isNaN(amount) ? 0 : amount).toString(), BitcoinUnit.LOCAL_CURRENCY, false);
break;
case BitcoinUnit.LOCAL_CURRENCY:
secondaryDisplayCurrency = currency.fiatToBTC(parseFloat(isNaN(amount) ? 0 : amount));
if (BlueBitcoinAmount.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY]) {
// cache hit! we reuse old value that supposedly doesn't have rounding errors
const sats = BlueBitcoinAmount.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY];
secondaryDisplayCurrency = currency.satoshiToBTC(sats);
}
break;
}
if (amount === BitcoinUnit.MAX) secondaryDisplayCurrency = ''; // we don't want to display NaN
return (
<TouchableWithoutFeedback disabled={this.props.pointerEvents === 'none'} onPress={() => this.textInput.focus()}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
{!this.props.disabled && <View style={{ alignSelf: 'center', padding: amount === BitcoinUnit.MAX ? 0 : 15 }} />}
<View style={{ flex: 1 }}>
<View
style={{ flexDirection: 'row', alignContent: 'space-between', justifyContent: 'center', paddingTop: 16, paddingBottom: 2 }}
>
{this.state.unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX && (
<Text
style={{
color: this.props.disabled
? BlueCurrentTheme.colors.buttonDisabledTextColor
: BlueCurrentTheme.colors.alternativeTextColor2,
fontSize: 18,
marginHorizontal: 4,
fontWeight: 'bold',
alignSelf: 'center',
justifyContent: 'center',
}}
>
{currency.getCurrencySymbol() + ' '}
</Text>
)}
<TextInput
{...this.props}
testID="BitcoinAmountInput"
keyboardType="numeric"
adjustsFontSizeToFit
onChangeText={text => {
text = text.trim();
if (this.state.unit !== BitcoinUnit.LOCAL_CURRENCY) {
text = text.replace(',', '.');
const split = text.split('.');
if (split.length >= 2) {
text = `${parseInt(split[0], 10)}.${split[1]}`;
} else {
text = `${parseInt(split[0], 10)}`;
}
text = this.state.unit === BitcoinUnit.BTC ? text.replace(/[^0-9.]/g, '') : text.replace(/[^0-9]/g, '');
if (text.startsWith('.')) {
text = '0.';
}
} else if (this.state.unit === BitcoinUnit.LOCAL_CURRENCY) {
text = text.replace(/,/gi, '');
if (text.split('.').length > 2) {
// too many dots. stupid code to remove all but first dot:
let rez = '';
let first = true;
for (const part of text.split('.')) {
rez += part;
if (first) {
rez += '.';
first = false;
}
}
text = rez;
}
text = text.replace(/[^\d.,-]/g, ''); // remove all but numbers, dots & commas
text = text.replace(/(\..*)\./g, '$1');
}
this.props.onChangeText(text);
}}
onBlur={() => {
if (this.props.onBlur) this.props.onBlur();
}}
onFocus={() => {
if (this.props.onFocus) this.props.onFocus();
}}
placeholder="0"
maxLength={this.maxLength()}
ref={textInput => (this.textInput = textInput)}
editable={!this.props.isLoading && !this.props.disabled}
value={amount === BitcoinUnit.MAX ? loc.units.MAX : parseFloat(amount) >= 0 ? amount : undefined}
placeholderTextColor={
this.props.disabled ? BlueCurrentTheme.colors.buttonDisabledTextColor : BlueCurrentTheme.colors.alternativeTextColor2
}
style={{
color: this.props.disabled
? BlueCurrentTheme.colors.buttonDisabledTextColor
: BlueCurrentTheme.colors.alternativeTextColor2,
fontWeight: 'bold',
fontSize: amount.length > 10 ? 20 : 36,
}}
/>
{this.state.unit !== BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX && (
<Text
style={{
color: this.props.disabled
? BlueCurrentTheme.colors.buttonDisabledTextColor
: BlueCurrentTheme.colors.alternativeTextColor2,
fontSize: 15,
marginHorizontal: 4,
fontWeight: '600',
alignSelf: 'center',
justifyContent: 'center',
}}
>
{' ' + loc.units[this.state.unit]}
</Text>
)}
</View>
<View style={{ alignItems: 'center', marginBottom: 22 }}>
<Text style={{ fontSize: 16, color: '#9BA0A9', fontWeight: '600' }}>
{this.state.unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX
? removeTrailingZeros(secondaryDisplayCurrency)
: secondaryDisplayCurrency}
{this.state.unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX ? ` ${loc.units[BitcoinUnit.BTC]}` : null}
</Text>
</View>
</View>
{!this.props.disabled && amount !== BitcoinUnit.MAX && (
<TouchableOpacity
testID="changeAmountUnitButton"
style={{ alignSelf: 'center', marginRight: 16, paddingLeft: 16, paddingVertical: 16 }}
onPress={this.changeAmountUnit}
>
<Image source={require('./img/round-compare-arrows-24-px.png')} />
</TouchableOpacity>
)}
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = StyleSheet.create({
balanceBlur: {
height: 30,

View file

@ -76,7 +76,7 @@ import LnurlPaySuccess from './screen/lnd/lnurlPaySuccess';
import LoadingScreen from './LoadingScreen';
import UnlockWith from './UnlockWith';
import DrawerList from './screen/wallets/drawerList';
import { isTablet } from 'react-native-device-info';
import { isCatalyst, isTablet } from './blue_modules/environment';
import SettingsPrivacy from './screen/settings/SettingsPrivacy';
import LNDViewAdditionalInvoicePreImage from './screen/lnd/lndViewAdditionalInvoicePreImage';
@ -348,7 +348,8 @@ const ReorderWalletsStackRoot = () => {
const Drawer = createDrawerNavigator();
function DrawerRoot() {
const dimensions = useWindowDimensions();
const isLargeScreen = Platform.OS === 'android' ? isTablet() : dimensions.width >= Dimensions.get('screen').width / 2 && isTablet();
const isLargeScreen =
Platform.OS === 'android' ? isTablet() : dimensions.width >= Dimensions.get('screen').width / 2 && (isTablet() || isCatalyst);
const drawerStyle = { width: '0%' };
return (

View file

@ -136,7 +136,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "6.0.6"
versionName "6.0.7"
multiDexEnabled true
missingDimensionStrategy 'react-native-camera', 'general'
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type

View file

@ -1,5 +1,5 @@
import { useAsyncStorage } from '@react-native-async-storage/async-storage';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
function BlueClipboard() {
BlueClipboard.STORAGE_KEY = 'ClipboardReadAllowed';

View file

@ -1,7 +1,8 @@
import { getSystemName } from 'react-native-device-info';
import { getSystemName, isTablet } from 'react-native-device-info';
import isCatalyst from 'react-native-is-catalyst';
const isMacCatalina = getSystemName() === 'Mac OS X';
module.exports.isMacCatalina = isMacCatalina;
module.exports.isCatalyst = isCatalyst;
module.exports.isTablet = isTablet;

View file

@ -7,7 +7,7 @@ import DocumentPicker from 'react-native-document-picker';
import isCatalyst from 'react-native-is-catalyst';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import { presentCameraNotAuthorizedAlert } from '../class/camera';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import ActionSheet from '../screen/ActionSheet';
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');

120
components/AddressInput.js Normal file
View file

@ -0,0 +1,120 @@
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import { Text } from 'react-native-elements';
import { findNodeHandle, Image, Keyboard, StyleSheet, TextInput, TouchableOpacity, View } from 'react-native';
import { getSystemName } from 'react-native-device-info';
import { useTheme } from '@react-navigation/native';
import loc from '../loc';
import * as NavigationService from '../NavigationService';
const fs = require('../blue_modules/fs');
const isDesktop = getSystemName() === 'Mac OS X';
const AddressInput = ({
isLoading = false,
address = '',
placeholder = loc.send.details_address,
onChangeText,
onBarScanned,
launchedBy,
}) => {
const { colors } = useTheme();
const scanButtonRef = useRef();
const stylesHook = StyleSheet.create({
root: {
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
backgroundColor: colors.inputBackgroundColor,
},
scan: {
backgroundColor: colors.scanLabel,
},
scanText: {
color: colors.inverseForegroundColor,
},
});
return (
<View style={[styles.root, stylesHook.root]}>
<TextInput
testID="AddressInput"
onChangeText={onChangeText}
placeholder={placeholder}
numberOfLines={1}
placeholderTextColor="#81868e"
value={address}
style={styles.input}
editable={!isLoading}
onSubmitEditing={Keyboard.dismiss}
/>
<TouchableOpacity
testID="BlueAddressInputScanQrButton"
disabled={isLoading}
onPress={() => {
Keyboard.dismiss();
if (isDesktop) {
fs.showActionSheet({ anchor: findNodeHandle(scanButtonRef.current) }).then(onBarScanned);
} else {
NavigationService.navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
params: {
launchedBy,
onBarScanned,
},
});
}
}}
style={[styles.scan, stylesHook.scan]}
>
<Image source={require('../img/scan-white.png')} />
<Text style={[styles.scanText, stylesHook.scanText]}>{loc.send.details_scan}</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
root: {
flexDirection: 'row',
borderWidth: 1.0,
borderBottomWidth: 0.5,
minHeight: 44,
height: 44,
marginHorizontal: 20,
alignItems: 'center',
marginVertical: 8,
borderRadius: 4,
},
input: {
flex: 1,
marginHorizontal: 8,
minHeight: 33,
color: '#81868e',
},
scan: {
height: 36,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
borderRadius: 4,
paddingVertical: 4,
paddingHorizontal: 8,
marginHorizontal: 4,
},
scanText: {
marginLeft: 4,
},
});
AddressInput.propTypes = {
isLoading: PropTypes.bool,
onChangeText: PropTypes.func,
onBarScanned: PropTypes.func.isRequired,
launchedBy: PropTypes.string,
address: PropTypes.string,
placeholder: PropTypes.string,
};
export default AddressInput;

313
components/AmountInput.js Normal file
View file

@ -0,0 +1,313 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import BigNumber from 'bignumber.js';
import { Text } from 'react-native-elements';
import { Image, StyleSheet, TextInput, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
import { useTheme } from '@react-navigation/native';
import { BitcoinUnit } from '../models/bitcoinUnits';
import loc, { formatBalanceWithoutSuffix, formatBalancePlain, removeTrailingZeros } from '../loc';
const currency = require('../blue_modules/currency');
class AmountInput extends Component {
static propTypes = {
isLoading: PropTypes.bool,
/**
* amount is a sting thats always in current unit denomination, e.g. '0.001' or '9.43' or '10000'
*/
amount: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
* callback that returns currently typed amount, in current denomination, e.g. 0.001 or 10000 or $9.34
* (btc, sat, fiat)
*/
onChangeText: PropTypes.func.isRequired,
/**
* callback thats fired to notify of currently selected denomination, returns <BitcoinUnit.*>
*/
onAmountUnitChange: PropTypes.func.isRequired,
disabled: PropTypes.bool,
colors: PropTypes.object.isRequired,
pointerEvents: PropTypes.string,
unit: PropTypes.string,
onBlur: PropTypes.func,
onFocus: PropTypes.func,
};
/**
* cache of conversions fiat amount => satoshi
* @type {{}}
*/
static conversionCache = {};
static getCachedSatoshis = amount => {
return AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY] || false;
};
static setCachedSatoshis = (amount, sats) => {
AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY] = sats;
};
/**
* here we must recalculate old amont value (which was denominated in `previousUnit`) to new denomination `newUnit`
* and fill this value in input box, so user can switch between, for example, 0.001 BTC <=> 100000 sats
*
* @param previousUnit {string} one of {BitcoinUnit.*}
* @param newUnit {string} one of {BitcoinUnit.*}
*/
onAmountUnitChange(previousUnit, newUnit) {
const amount = this.props.amount || 0;
console.log('was:', amount, previousUnit, '; converting to', newUnit);
let sats = 0;
switch (previousUnit) {
case BitcoinUnit.BTC:
sats = new BigNumber(amount).multipliedBy(100000000).toString();
break;
case BitcoinUnit.SATS:
sats = amount;
break;
case BitcoinUnit.LOCAL_CURRENCY:
sats = new BigNumber(currency.fiatToBTC(amount)).multipliedBy(100000000).toString();
break;
}
if (previousUnit === BitcoinUnit.LOCAL_CURRENCY && AmountInput.conversionCache[amount + previousUnit]) {
// cache hit! we reuse old value that supposedly doesnt have rounding errors
sats = AmountInput.conversionCache[amount + previousUnit];
}
console.log('so, in sats its', sats);
const newInputValue = formatBalancePlain(sats, newUnit, false);
console.log('and in', newUnit, 'its', newInputValue);
if (newUnit === BitcoinUnit.LOCAL_CURRENCY && previousUnit === BitcoinUnit.SATS) {
// we cache conversion, so when we will need reverse conversion there wont be a rounding error
AmountInput.conversionCache[newInputValue + newUnit] = amount;
}
this.props.onChangeText(newInputValue);
this.props.onAmountUnitChange(newUnit);
}
/**
* responsible for cycling currently selected denomination, BTC->SAT->LOCAL_CURRENCY->BTC
*/
changeAmountUnit = () => {
let previousUnit = this.props.unit;
let newUnit;
if (previousUnit === BitcoinUnit.BTC) {
newUnit = BitcoinUnit.SATS;
} else if (previousUnit === BitcoinUnit.SATS) {
newUnit = BitcoinUnit.LOCAL_CURRENCY;
} else if (previousUnit === BitcoinUnit.LOCAL_CURRENCY) {
newUnit = BitcoinUnit.BTC;
} else {
newUnit = BitcoinUnit.BTC;
previousUnit = BitcoinUnit.SATS;
}
this.onAmountUnitChange(previousUnit, newUnit);
};
maxLength = () => {
switch (this.props.unit) {
case BitcoinUnit.BTC:
return 10;
case BitcoinUnit.SATS:
return 15;
default:
return 15;
}
};
textInput = React.createRef();
handleTextInputOnPress = () => {
this.textInput.current.focus();
};
handleChangeText = text => {
text = text.trim();
if (this.props.unit !== BitcoinUnit.LOCAL_CURRENCY) {
text = text.replace(',', '.');
const split = text.split('.');
if (split.length >= 2) {
text = `${parseInt(split[0], 10)}.${split[1]}`;
} else {
text = `${parseInt(split[0], 10)}`;
}
text = this.props.unit === BitcoinUnit.BTC ? text.replace(/[^0-9.]/g, '') : text.replace(/[^0-9]/g, '');
if (text.startsWith('.')) {
text = '0.';
}
} else if (this.props.unit === BitcoinUnit.LOCAL_CURRENCY) {
text = text.replace(/,/gi, '');
if (text.split('.').length > 2) {
// too many dots. stupid code to remove all but first dot:
let rez = '';
let first = true;
for (const part of text.split('.')) {
rez += part;
if (first) {
rez += '.';
first = false;
}
}
text = rez;
}
text = text.replace(/[^\d.,-]/g, ''); // remove all but numbers, dots & commas
text = text.replace(/(\..*)\./g, '$1');
}
this.props.onChangeText(text);
};
render() {
const { colors, disabled, unit } = this.props;
const amount = this.props.amount || 0;
let secondaryDisplayCurrency = formatBalanceWithoutSuffix(amount, BitcoinUnit.LOCAL_CURRENCY, false);
// if main display is sat or btc - secondary display is fiat
// if main display is fiat - secondary dislay is btc
let sat;
switch (unit) {
case BitcoinUnit.BTC:
sat = new BigNumber(amount).multipliedBy(100000000).toString();
secondaryDisplayCurrency = formatBalanceWithoutSuffix(sat, BitcoinUnit.LOCAL_CURRENCY, false);
break;
case BitcoinUnit.SATS:
secondaryDisplayCurrency = formatBalanceWithoutSuffix((isNaN(amount) ? 0 : amount).toString(), BitcoinUnit.LOCAL_CURRENCY, false);
break;
case BitcoinUnit.LOCAL_CURRENCY:
secondaryDisplayCurrency = currency.fiatToBTC(parseFloat(isNaN(amount) ? 0 : amount));
if (AmountInput.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY]) {
// cache hit! we reuse old value that supposedly doesn't have rounding errors
const sats = AmountInput.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY];
secondaryDisplayCurrency = currency.satoshiToBTC(sats);
}
break;
}
if (amount === BitcoinUnit.MAX) secondaryDisplayCurrency = ''; // we don't want to display NaN
const stylesHook = StyleSheet.create({
center: { padding: amount === BitcoinUnit.MAX ? 0 : 15 },
localCurrency: { color: disabled ? colors.buttonDisabledTextColor : colors.alternativeTextColor2 },
input: { color: disabled ? colors.buttonDisabledTextColor : colors.alternativeTextColor2, fontSize: amount.length > 10 ? 20 : 36 },
cryptoCurrency: { color: disabled ? colors.buttonDisabledTextColor : colors.alternativeTextColor2 },
});
return (
<TouchableWithoutFeedback disabled={this.props.pointerEvents === 'none'} onPress={() => this.textInput.focus()}>
<View style={styles.root}>
{!disabled && <View style={[styles.center, stylesHook.center]} />}
<View style={styles.flex}>
<View style={styles.container}>
{unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX && (
<Text style={[styles.localCurrency, stylesHook.localCurrency]}>{currency.getCurrencySymbol() + ' '}</Text>
)}
<TextInput
{...this.props}
testID="BitcoinAmountInput"
keyboardType="numeric"
adjustsFontSizeToFit
onChangeText={this.handleChangeText}
onBlur={() => {
if (this.props.onBlur) this.props.onBlur();
}}
onFocus={() => {
if (this.props.onFocus) this.props.onFocus();
}}
placeholder="0"
maxLength={this.maxLength()}
ref={textInput => (this.textInput = textInput)}
editable={!this.props.isLoading && !disabled}
value={amount === BitcoinUnit.MAX ? loc.units.MAX : parseFloat(amount) >= 0 ? String(amount) : undefined}
placeholderTextColor={disabled ? colors.buttonDisabledTextColor : colors.alternativeTextColor2}
style={[styles.input, stylesHook.input]}
/>
{unit !== BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX && (
<Text style={[styles.cryptoCurrency, stylesHook.cryptoCurrency]}>{' ' + loc.units[unit]}</Text>
)}
</View>
<View style={styles.secondaryRoot}>
<Text style={styles.secondaryText}>
{unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX
? removeTrailingZeros(secondaryDisplayCurrency)
: secondaryDisplayCurrency}
{unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX ? ` ${loc.units[BitcoinUnit.BTC]}` : null}
</Text>
</View>
</View>
{!disabled && amount !== BitcoinUnit.MAX && (
<TouchableOpacity testID="changeAmountUnitButton" style={styles.changeAmountUnit} onPress={this.changeAmountUnit}>
<Image source={require('../img/round-compare-arrows-24-px.png')} />
</TouchableOpacity>
)}
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = StyleSheet.create({
root: {
flexDirection: 'row',
justifyContent: 'space-between',
},
center: {
alignSelf: 'center',
},
flex: {
flex: 1,
},
container: {
flexDirection: 'row',
alignContent: 'space-between',
justifyContent: 'center',
paddingTop: 16,
paddingBottom: 2,
},
localCurrency: {
fontSize: 18,
marginHorizontal: 4,
fontWeight: 'bold',
alignSelf: 'center',
justifyContent: 'center',
},
input: {
fontWeight: 'bold',
},
cryptoCurrency: {
fontSize: 15,
marginHorizontal: 4,
fontWeight: '600',
alignSelf: 'center',
justifyContent: 'center',
},
secondaryRoot: {
alignItems: 'center',
marginBottom: 22,
},
secondaryText: {
fontSize: 16,
color: '#9BA0A9',
fontWeight: '600',
},
changeAmountUnit: {
alignSelf: 'center',
marginRight: 16,
paddingLeft: 16,
paddingVertical: 16,
},
});
const AmountInputWithStyle = props => {
const { colors } = useTheme();
return <AmountInput {...props} colors={colors} />;
};
// expose static methods
AmountInputWithStyle.conversionCache = AmountInput.conversionCache;
AmountInputWithStyle.getCachedSatoshis = AmountInput.getCachedSatoshis;
AmountInputWithStyle.setCachedSatoshis = AmountInput.setCachedSatoshis;
export default AmountInputWithStyle;

View file

@ -1630,7 +1630,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -1673,7 +1673,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -1714,7 +1714,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.TodayExtension;
@ -1753,7 +1753,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.TodayExtension;
PRODUCT_NAME = "BlueWallet - Bitcoin Price";
@ -1785,7 +1785,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = Stickers/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
@ -1816,7 +1816,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = Stickers/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1852,7 +1852,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.PriceWidget;
@ -1894,7 +1894,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.PriceWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1934,7 +1934,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
@ -1977,7 +1977,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -2018,7 +2018,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.WalletInformationAndMarketWidget;
@ -2062,7 +2062,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.WalletInformationAndMarketWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -2102,7 +2102,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.WalletInformationWidget;
@ -2144,7 +2144,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.WalletInformationWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -2286,7 +2286,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
@ -2326,7 +2326,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
PRODUCT_NAME = "${TARGET_NAME}";
@ -2362,7 +2362,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
IBSC_MODULE = BlueWalletWatch_Extension;
INFOPLIST_FILE = BlueWalletWatch/Info.plist;
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;
@ -2401,7 +2401,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
IBSC_MODULE = BlueWalletWatch_Extension;
INFOPLIST_FILE = BlueWalletWatch/Info.plist;
MARKETING_VERSION = 6.0.6;
MARKETING_VERSION = 6.0.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;
PRODUCT_NAME = "$(TARGET_NAME)";

View file

@ -276,7 +276,7 @@ PODS:
- react-native-tcp-socket (3.7.1):
- CocoaAsyncSocket
- React
- react-native-webview (11.2.0):
- react-native-webview (11.2.1):
- React-Core
- react-native-widget-center (0.0.4):
- React
@ -347,7 +347,7 @@ PODS:
- React
- RNCAsyncStorage (1.13.4):
- React-Core
- RNCClipboard (1.5.1):
- RNCClipboard (1.7.0):
- React-Core
- RNCMaskedView (0.1.10):
- React
@ -470,7 +470,7 @@ DEPENDENCIES:
- RealmJS (from `../node_modules/realm`)
- "RemobileReactNativeQrcodeLocalImage (from `../node_modules/@remobile/react-native-qrcode-local-image`)"
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
- RNDefaultPreference (from `../node_modules/react-native-default-preference`)
@ -607,7 +607,7 @@ EXTERNAL SOURCES:
RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCClipboard:
:path: "../node_modules/@react-native-community/clipboard"
:path: "../node_modules/@react-native-clipboard/clipboard"
RNCMaskedView:
:path: "../node_modules/@react-native-community/masked-view"
RNCPushNotificationIOS:
@ -707,7 +707,7 @@ SPEC CHECKSUMS:
react-native-safe-area-context: 86612d2c9a9e94e288319262d10b5f93f0b395f5
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-tcp-socket: 96a4f104cdcc9c6621aafe92937f163d88447c5b
react-native-webview: c010115ea45efd0d329ac7746d0cc59579d7860c
react-native-webview: dbe6c1ad149740f0e2d84a963f1d3c3e77f2d99c
react-native-widget-center: 0f81d17beb163e7fb5848b06754d7d277fe7d99a
React-RCTActionSheet: 53ea72699698b0b47a6421cb1c8b4ab215a774aa
React-RCTAnimation: 1befece0b5183c22ae01b966f5583f42e69a83c2
@ -722,7 +722,7 @@ SPEC CHECKSUMS:
RealmJS: 5195064e9aeccf94ae3756bd9d0f2301b9074b07
RemobileReactNativeQrcodeLocalImage: 57aadc12896b148fb5e04bc7c6805f3565f5c3fa
RNCAsyncStorage: 0701cb7395f06d744184641241888a0eec0e2f2a
RNCClipboard: 5e299c6df8e0c98f3d7416b86ae563d3a9f768a3
RNCClipboard: dac13db8b1ce9b998f1cbc7ca33440113602847f
RNCMaskedView: f5c7d14d6847b7b44853f7acb6284c1da30a3459
RNCPushNotificationIOS: 5b1cf9ad2aaa107ecb92d5d2d7005ba521b2b97a
RNDefaultPreference: 21816c0a6f61a2829ccc0cef034392e9b509ee5f

View file

@ -1,3 +1,32 @@
v6.0.6
======
* ADD: PSBT cosign
* ADD: Long press Transaction Row to get shortcuts
* ADD: Tap and hold to Share QRCode image
* ADD: qrcode scanner to wallet/broadcast screen
* ADD: Apple Watch Price Complication
* ADD: Update complication currency based on user preference
* ADD: Copying Block Explorer Link
* ADD: If unable to connect to server, show alert
* FIX: Delete wallet button should be red
* FIX: Wallet delete would cause crash
* FIX: broken buyBitcoin button for some wallets
* FIX: Browser crash when accessing wallet
* FIX: sometimes broken webview
* FIX: Some widgets were not showing on drawer
* FIX: screen titles language
* FIX: Complication app update when watch app isnt launched
* FIX: QRCode save alert description
* FIX: Only send complication updates if watch is reachable
* FIX: QRCode size on large devices
* FIX: fix size and share button
* FIX: sync loc files for ar, ru, ca, he, pl, ja_JP, pt_BR, pt_PT, sv_SE, th_TH, zh_CN, fi_FI, fa_IR, de_DE, nl_NL, fr_FR
* REF: transactions/details screen gracefull error handling
* REF: electrum protocol error graceful handling
* REF: better bitcoinscript error handling
* REF: Fee selection in darkmode
v6.0.4
======
@ -48,48 +77,3 @@ v6.0.3
* FIX: multisig coin control
* REF: Remove "new" from LocalTrader
* FIX: locales fr_FR, sl_SI, es_ES, ru, fa_IR, fi_FI
v6.0.2
======
* ADD: view of QR code of Vault key zpub after vault is created (closes #2410)
* ADD: helper text on ms-edit screen
* ADD: electrum servers history list
* ADD: iMessage stickers
* ADD: Privacy settings for iOS 14 widgets
* ADD: ability to set electrum server or lndhub via deeplink or by scanning a QR from main screen
* ADD: CoinControl multiselect
* FIX: better support multisig cosigning with Electrum desktop
* FIX: multisig 'Too many signatures' error
* FIX: Amount displayed on success invoice payment
* FIX: localizations for fr_FR, es_ES, de_DE, fa_IR, cs_CZ, fr_FR, nl_NL, fi_FI
* FIX: Hide balance on reorder screen
* FIX: disallow importing non-multisignature xpubs into multisig setup
* FIX: better multisig wallet descriptors suppport
* FIX: Incorrect import from Specter - p2sh wrapped segwit multisig
* FIX: Clear quick actions if storage is encrypted
* FIX: use dayjs localizedFormat plugin to render tx time
* FIX: show more accurate precalculation fee on "Not enough balance." exception
* FIX: Wallet Delete on new install was not being triggered
* FIX: Fallback to English if case isn't found
* FIX: animated qr scan progress readability
* FIX: rerender UI after language change
* FIX: Hide modal when scanning
* FIX: reorder screen bug
* FIX: Don't show clipboard modal if user has already acted on it
* REF: processing push notifications
* REF: Add warning to LN
* REF: Github link on about
* DOC: Telegram and Discord links on about section
v6.0.1
======
* ADD: enable batch-send on multisig wallets
* FIX: Speed-up multisig wallets (disable handoff for multisig)
* FIX: Import Multisig from Specter Desktop - Fingerprint is Incorrect
* FIX: broken export .txn file on tx confirmation screen
* FIX: backup screen would flash during loading on dark mode
* FIX: Handle opening links if the default browser isnt Safari
* FIX: contradiction in Vaul introduction text
* FIX: localizations for CA, DE, ES, fa_IR, sl_SI, cs_CZ, pt_BR

View file

@ -1 +1 @@
BlueWallet - Bitcoin portomonnee
BlueWallet Bitcoin portomonnee

View file

@ -137,7 +137,7 @@
"ask_yes": "Ja, habe ich.",
"ok": "Ja, ich habe sie aufgeschrieben!",
"ok_lnd": "Die Sicherung ist erstellt.",
"text": "Nimm Dir Zeit die mnemonischen Wörter zur späteren Wiederherstellung des Wallets auf ein Papier zu schreiben. Die Wörter sind dein einziges Backup im Fall eines Geräteverlustes.",
"text": "Nimm Dir Zeit die mnemonische Phrase zur späteren Wiederherstellung auf Papier zu schreiben. Die Wörter sind dein Backup im Fall eines Geräteverlustes.",
"text_lnd": "Zur Wiederherstellung des Wallet im Verlustfall bitte dieses Wallet-Backup sichern. ",
"text_lnd2": "Diese Wallet wird durch BlueWallet verwaltet.",
"title": "Dein Wallet ist erstellt."
@ -274,7 +274,9 @@
"electrum_clear_alert_ok": "Ok",
"electrum_select": "Auswählen",
"electrum_reset": "Auf Standard zurücksetzen",
"electrum_unable_to_connect": "Verbindung zu {Server} kann nicht hergestellt werden.",
"electrum_history": "Serverhistorie",
"electrum_reset_to_default": "Sollen die Electrum-Einstellungen wirklich auf die Standardwerte zurückgesetzt werden?",
"electrum_clear": "Löschen",
"encrypt_decrypt": "Speicher entschlüsseln",
"encrypt_decrypt_q": "Willst du die Speicherverschlüsselung wirklich aufheben? Hiermit wird dein Wallet ohne Passwortschutz direkt benutzbar. ",
@ -329,7 +331,7 @@
"ask_me_later": "Später erneut fragen"
},
"transactions": {
"cancel_explain": "BlueWallet ersetzt diese Transaktion durch eine Transaktion mit höherer Gebühr, welche den Betrag an Dich zurücküberweist. Die Transaktion wird dadurch effektiv abgebrochen. Dies wird RBF genannt - Replace By Fee.",
"cancel_explain": "BlueWallet ersetzt diese Transaktion durch eine mit höherer Gebühr, welche den Betrag an Dich zurücküberweist. Die Transaktion wird dadurch effektiv abgebrochen. Dies wird RBF - Replace By Fee - genannt.",
"cancel_no": "Diese Transaktion ist nicht ersetzbar.",
"cancel_title": "Diese Transaktion abbrechen (RBF)",
"confirmations_lowercase": "{confirmations} Bestätigungen",
@ -349,7 +351,7 @@
"details_inputs": "Eingänge",
"details_outputs": "Ausgänge",
"details_received": "Empfangen",
"transaction_note_saved":"Transaktionsbezeichnung erfolgreich gespeichert.",
"transaction_note_saved": "Transaktionsbezeichnung erfolgreich gespeichert.",
"details_show_in_block_explorer": "Im Block-Explorer zeigen",
"details_title": "Transaktion",
"details_to": "Ausgehend",
@ -363,7 +365,7 @@
"status_bump": "TRX-Gebühr erhöhen",
"status_cancel": "Transaktion abbrechen",
"transactions_count": "Anzahl Transaktionen",
"txid": "TX-ID",
"txid": "Transaktions-ID",
"updating": "Aktualisiere...."
},
"wallets": {
@ -415,7 +417,7 @@
"export_title": "Wallet exportieren",
"import_do_import": "Importieren",
"import_error": "Fehler beim Import. Ist die Eingabe korrekt?",
"import_explanation": "Gib hier die mnemonische Phrase, den privaten Schlüssel, WIF oder was immer Du hast ein. BlueWallet wird bestmöglich das Format interpretieren und die Wallet importieren. Bei Eingabe eines öffentlichen Schlüssels wird ein \"Watch-only\" Wallet hinzugefügt.",
"import_explanation": "Gib hier die mnemonische Phrase, den privaten Schlüssel, WIF oder was immer Du hast ein. BlueWallet wird bestmöglich das Format interpretieren und die Wallet importieren.",
"import_file": "Datei importieren",
"import_imported": "Importiert",
"import_placeholder_fail": "Wallet importieren",
@ -428,7 +430,7 @@
"list_create_a_wallet_text": "Wallets sind kostenlos. \nErstelle so viel du magst.",
"list_empty_txs1": "Deine Transaktionen erscheinen hier",
"list_empty_txs1_lightning": "Verwende das Lightning Wallet für Deine täglichen Bezahlungen. Lightning Transaktionen sind konkurrenzlos günstig und verblüffend schnell.",
"list_empty_txs2": "Noch keine Transaktionen",
"list_empty_txs2": "Beginne mit deinem Wallet.",
"list_empty_txs2_lightning": "\nDrücke zum Starten «Beträge verwalten», um das Wallet aufzuladen.",
"list_header": "Eine Wallet beinhaltet ein Schlüsselpaar - einen privaten Schlüssel und einen öffentlichen, welcher veröffentlicht werden kann, um Zahlungen zu erhalten.",
"list_import_error": "Beim Versuch, diese Wallet zu importieren, ist ein Fehler aufgetreten. ",

View file

@ -180,7 +180,7 @@
"details_amount_field_is_not_valid": "The amount is not valid.",
"details_amount_field_is_less_than_minimum_amount_sat": "The specified amount is too small. Please enter an amount greater than 500 sats.",
"details_create": "Create Invoice",
"details_error_decode": "Error: Unable to decode Bitcoin address",
"details_error_decode": "Unable to decode Bitcoin address",
"details_fee_field_is_not_valid": "The fee is not valid.",
"details_next": "Next",
"details_no_maximum": "The selected wallet doesnt support automatic maximum balance calculation. Are you sure to want to select this wallet?",
@ -189,6 +189,7 @@
"details_note_placeholder": "Note to Self",
"details_scan": "Scan",
"details_total_exceeds_balance": "The sending amount exceeds the available balance.",
"details_unrecognized_file_format": "Unrecognized file format",
"details_wallet_before_tx": "Before creating a transaction, you must first add a Bitcoin wallet.",
"details_wallet_selection": "Wallet Selection",
"dynamic_init": "Initializing",

View file

@ -180,7 +180,7 @@
"details_amount_field_is_not_valid": "مقدار معتبر نیست.",
"details_amount_field_is_less_than_minimum_amount_sat": "مقدار تعیین‌شده بسیار کم است. لطفاً مقداری بیشتر از ۵۰۰ ساتوشی را وارد کنید.",
"details_create": "ایجاد صورت‌حساب",
"details_error_decode": "خطا: ناموفق در رمزگشایی آدرس بیت‌کوین",
"details_error_decode": "ناموفق در رمزگشایی آدرس بیت‌کوین",
"details_fee_field_is_not_valid": "کارمزد معتبر نیست.",
"details_next": "بعدی",
"details_no_maximum": "کیف پول انتخاب‌شده از محاسبهٔ خودکار حداکثر موجودی پشتیبانی نمی‌کند. آیا مطمئن هستید که می‌خواهید این کیف پول را انتخاب کنید؟",
@ -189,6 +189,7 @@
"details_note_placeholder": "یادداشت به خود",
"details_scan": "اسکن",
"details_total_exceeds_balance": "مقدار ارسالی بیش از ماندهٔ موجود است.",
"details_unrecognized_file_format": "قالب فایل ناشناخته",
"details_wallet_before_tx": "قبل از ایجاد تراکنش، ابتدا باید یک کیف پول بیت‌کوین اضافه کنید.",
"details_wallet_selection": "انتخاب کیف پول",
"dynamic_init": "درحال راه‌اندازی",
@ -274,7 +275,9 @@
"electrum_clear_alert_ok": "بله",
"electrum_select": "انتخاب",
"electrum_reset": "بازنشانی به پیش‌فرض",
"electrum_unable_to_connect": "ناموفق در اتصال به {server}",
"electrum_history": "تاریخچهٔ سرورها",
"electrum_reset_to_default": "آیا مطمئن هستید که می‌خواهید تنظیمات الکترام را به حالت پیش‌فرض بازنشانی کنید؟",
"electrum_clear": "پاک‌کردن",
"encrypt_decrypt": "رمزگشایی فضای ذخیره‌سازی",
"encrypt_decrypt_q": "آیا مطمئن هستید که می‌خواهید فضای ذخیره‌سازی خود را رمزگشایی کنید؟ این کار اجازه می‌دهد تا کیف پول‌های شما بدون گذرواژه قابل‌دسترسی باشند.",
@ -333,6 +336,10 @@
"cancel_no": "این تراکنش قابل‌جایگزینی نیست.",
"cancel_title": "این تراکنش را لغو کن (RBF)",
"confirmations_lowercase": "{confirmations} تأیید",
"transaction_id": "شناسهٔ تراکنش",
"note": "یادداشت",
"expand_note": "نمایش کامل یادداشت",
"block_explorer_link": "لینک مرورگر بلاک",
"cpfp_create": "ایجاد",
"cpfp_exp": "ما تراکنش دیگری را ایجاد خواهیم کرد که تراکنش تأییدنشدهٔ شما را خرج می‌کند. کارمزد کل بالاتر از کارمزد تراکنش اصلی خواهد بود، بنابراین سریع‌تر استخراج می‌شود. این کار Child Pays for Parent (به‌اختصار CPFP) نام دارد—فرزند به‌جای والدین می‌پردازد.",
"cpfp_no_bump": "این تراکنش قابلیت افزایش کارمزد ندارد.",
@ -345,7 +352,7 @@
"details_inputs": "ورودی‌ها",
"details_outputs": "خروجی‌ها",
"details_received": "دریافت‌شده",
"transaction_note_saved":"یادداشت تراکنش با موفقیت ذخیره شد.",
"transaction_note_saved": "یادداشت تراکنش با موفقیت ذخیره شد.",
"details_show_in_block_explorer": "مشاهده در مرورگر بلاک",
"details_title": "تراکنش",
"details_to": "خروجی",
@ -411,7 +418,7 @@
"export_title": "صادرکردن کیف پول",
"import_do_import": "واردکردن",
"import_error": "واردکردن ناموفق بود. لطفاً از معتبربودن دادهٔ ارائه‌شده اطمینان حاصل کنید.",
"import_explanation": "عبارت یادیار (mnemonic phrase)، کلید خصوصی، WIF، یا هر چیزی را که دارید اینجا بنویسید. BlueWallet تمام تلاش خود را برای حدس‌زدن قالب صحیح و واردکردن کیف پول شما انجام خواهد داد. درصورت واردکردن کلید عمومی، ما آن را به‌صورت کیف پول watch-only اضافه خواهیم کرد.",
"import_explanation": "لطفاً کلمه‌های سید، کلید عمومی، WIF، یا هر چیزی را که دارید وارد کنید. BlueWallet تمام تلاش خود را برای حدس‌زدن قالب صحیح و واردکردن کیف پول شما انجام خواهد داد.",
"import_file": "واردکردن فایل",
"import_imported": "وارد شد",
"import_placeholder_fail": "واردکردن کیف پول",
@ -424,7 +431,7 @@
"list_create_a_wallet_text": "مجانی است، و می‌توانید هر تعداد\nکه دوست داشتید بسازید.",
"list_empty_txs1": "تراکنش‌های شما در اینجا نمایش داده خواهند شد.",
"list_empty_txs1_lightning": "برای تراکنش‌های روزمره بهتر است از کیف پول لایتنینگ استفاده شود. کارمزدها به‌طرز غیرمنصفانه‌ای ارزان و سرعت فوق‌العاده بالاست.",
"list_empty_txs2": "با کیف پول خود شروع کنید",
"list_empty_txs2": "با کیف پول خود شروع کنید.",
"list_empty_txs2_lightning": "\nبرای شروع استفاده، روی «مدیریت دارایی» بزنید و موجودی خود را شارژ کنید.",
"list_header": "کیف پول نشانگر یک جفت کلید است—یکی خصوصی و یکی که می‌توانید آن را برای دریافت بیت‌کوین به‌اشتراک بگذارید.",
"list_import_error": "خطایی هنگام تلاش برای واردکردن این کیف پول رخ داد.",

View file

@ -15,7 +15,7 @@
"save": "Tallenna",
"seed": "Siemen",
"wallet_key": "Lompakkoavain",
"invalid_animated_qr_code_fragment": "Virheellinen animoitu QRCode-fragmentti, yritä uudelleen",
"invalid_animated_qr_code_fragment" : "Virheellinen animoitu QRCode-fragmentti, yritä uudelleen",
"file_saved": "Tiedosto ({filePath}) on tallennettu Lataukset-kansioon.",
"discard_changes": "Hylkää muutokset?",
"discard_changes_detail": "Sinulla on tallentamattomia muutoksia. Haluatko varmasti hylätä ne ja poistut näytöltä? "
@ -137,7 +137,7 @@
"ask_yes": "Kyllä, olen",
"ok": "OK, kirjoitan tämän ylös!",
"ok_lnd": "OK, olen tallentanut sen.",
"text": "Ole hyvä ja ota hetki kirjoittaaksesi tämä muistilauseke paperille. Se on varmuuskopio, jonka avulla voit palauttaa lompakon toisella laitteella.",
"text": "Käytä hetki muistilausekkeen kirjoittamiseen paperille. Se on varmuuskopiosi, jolla voit palauttaa lompakon toisella laitteella. ",
"text_lnd": "Tallenna tämä lompakon varmuuskopio. Sen avulla voit palauttaa lompakon, jos lompakko katoaa.",
"text_lnd2": "Tätä lompakkoa ylläpitää BlueWallet.",
"title": "Lompakkosi on luotu"
@ -274,7 +274,9 @@
"electrum_clear_alert_ok": "Ok",
"electrum_select": "Valitse",
"electrum_reset": "Palauta oletusasetuksiin",
"electrum_unable_to_connect": " Ei saada yhteyttä {server}. ",
"electrum_history": "Palvelimen historia",
"electrum_reset_to_default": "Haluatko varmasti palauttaa Electrumin asetukset oletusarvoihin? ",
"electrum_clear": "Tyhjennä",
"encrypt_decrypt": "Pura tallennustilan salaus",
"encrypt_decrypt_q": "Haluatko varmasti purkaa tallennustilan salauksen? Tämä mahdollistaa lompakkoihisi pääsyn ilman salasanaa.",
@ -302,7 +304,7 @@
"network_electrum": "Electrum-palvelin",
"not_a_valid_uri": "URI ei kelpaa",
"notifications": "Ilmoitukset",
"open_link_in_explorer": "Avaa linkki selaimessa",
"open_link_in_explorer" : "Avaa linkki selaimessa",
"password": "Salasana",
"password_explain": "Luo salasana, jota käytät tallennustilan salauksen purkamiseen",
"passwords_do_not_match": "Salasanat eivät täsmää",
@ -318,7 +320,7 @@
"retype_password": "Salasana uudelleen",
"save": "Tallenna",
"saved": "Tallennettu",
"success_transaction_broadcasted": "Onnistui! Siirtotapahtumasi on lähetetty!",
"success_transaction_broadcasted" : "Onnistui! Siirtotapahtumasi on lähetetty!",
"total_balance": "Kokonaissaldo",
"total_balance_explanation": "Näytä kaikkien lompakoiden kokonaissaldo aloitusnäytön widgeteissä.",
"widgets": "Widgetit"
@ -329,10 +331,14 @@
"ask_me_later": "Kysy Minulta Myöhemmin"
},
"transactions": {
"cancel_explain": "Korvaamme tämän siirtotapahtuman sillä, joka maksaa sinulle ja on korkeammat siirtokulut. Tämä peruuttaa siirtotapahtuman tehokkaasti. Tätä kutsutaan RBF - Replace By Fee - Korvaa korkeammilla kuluilla.",
"cancel_explain": "Korvaamme tämän siirtotapahtuman sillä, joka maksaa sinulle ja jossa on korkeammat siirtokulut. Tämä peruu siirtotapahtuman käytännössä. Tätä kutsutaan RBF - Replace By Fee. ",
"cancel_no": "Tämä siirtotapahtuma ei ole vaihdettavissa",
"cancel_title": "Peruuta tämä siirtotapahtuma (RBF)",
"confirmations_lowercase": "{confirmations} vahvistukset",
"transaction_id": "Siirtotapahtuman tunnus",
"note": "Huomautus",
"expand_note": "Laajenna huomautus",
"block_explorer_link": "Lohkoselain-linkki",
"cpfp_create": "Luo",
"cpfp_exp": "Luomme toisen siirtotapahtuman, joka kuluttaa vahvistamattoman siirtotapahtuman. Kokonaiskulu on suurempi kuin alkuperäinen siirtokulu, joten sen pitäisi olla louhittu nopeammin. Tätä kutsutaan CPFP - Child Pays For Parent - Lapsi Maksaa Vanhemmalle.",
"cpfp_no_bump": "Tämä siirtotapahtuma ei ole nostettavissa",
@ -359,7 +365,7 @@
"status_bump": "Nosta siirtokuluja",
"status_cancel": "Peruuta Siirtotapahtuma",
"transactions_count": "siirtotapahtumien määrä",
"txid": "Siirtotunniste",
"txid": "Siirtotapahtuman tunnus",
"updating": "Päivitetään..."
},
"wallets": {
@ -411,7 +417,7 @@
"export_title": "lompakon vienti",
"import_do_import": "Tuo",
"import_error": "Tuonti epäonnistui. Varmista, että annettu tieto on oikein",
"import_explanation": "Kirjoita tähän muistilauseke, yksityinen avain, WIF tai mikä tahansa sinulla on. BlueWallet tekee parhaansa arvatakseen oikean muodon ja tuodakseen lompakkosi. Jos syötetään julkinen avain, lisätään se vain katselu-lompakoksi.",
"import_explanation": "Kirjoita siemensanasi, julkinen avain, WIF tai mikä tahansa sinulla on. BlueWallet tekee parhaansa arvatakseen oikean formaatin ja tuodakseen lompakkosi. ",
"import_file": "Tuo tiedosto",
"import_imported": "Tuotu",
"import_placeholder_fail": "Lompakon tuonti",
@ -424,7 +430,7 @@
"list_create_a_wallet_text": "Se on ilmainen ja voit luoda\nniin monta kuin haluat",
"list_empty_txs1": "Siirtotapahtumasi näkyvät tässä,",
"list_empty_txs1_lightning": "Lightning-lompakkoa tulisi käyttää päivittäisiin siirtotapahtumiin. Siirtokulut ovat kohtuuttoman halpoja ja nopeus on liekehtivän kova.",
"list_empty_txs2": "Aloita lompakostasi",
"list_empty_txs2": "Aloita lompakostasi. ",
"list_empty_txs2_lightning": "Aloita sen käyttäminen napsauttamalla \"hallinnoi varoja\" ja lisää saldoasi.\n",
"list_header": "Lompakko edustaa avainparia, yhtä yksityistä ja yhtä, jonka voit jakaa vastaanottaaksesi kolikoita.",
"list_import_error": "Tämän lompakon tuomisessa tapahtui virhe.",
@ -468,7 +474,7 @@
"share": "Jaa",
"view": "Näytä",
"manage_keys": "Hallitse Avaimia",
"how_many_signatures_can_bluewallet_make": "kuinka monta allekirjoitusta bluewallet voi tehdä",
"how_many_signatures_can_bluewallet_make": "kuinka monta allekirjoitusta BlueWallet voi tehdä",
"signatures_required_to_spend": "Vaaditaan allekirjoituksia {number}",
"signatures_we_can_make": "voidaan tehdä {number}",
"scan_or_import_file": "Skannaa tai tuo tiedosto",

View file

@ -274,7 +274,9 @@
"electrum_clear_alert_ok": "Ok",
"electrum_select": "Selectionner",
"electrum_reset": "Réinitialiser au valeurs par défaut",
"electrum_unable_to_connect": "Impossible de se connecter à {server}.",
"electrum_history": "Historique de serveur",
"electrum_reset_to_default": "Etes-vous sûr de vouloir réinitialiser vos paramètres Electrum ?",
"electrum_clear": "Effacer",
"encrypt_decrypt": "Déchiffrer le stockage",
"encrypt_decrypt_q": "Etes-vous sûr de vouloir déchiffrer le stockage ? L'accès à vos portefeuilles pourra alors se faire sans mot de passe.",
@ -329,10 +331,14 @@
"ask_me_later": "Me demander plus tard"
},
"transactions": {
"cancel_explain": "Nous allons remplacer cette transaction par celle où les fonds vous reviennet et a de plus hauts frais. Cela annulera la transaction. On parle de RBF - Replace By Fee.",
"cancel_explain": "Nous allons remplacer cette transaction par celle où les fonds vous reviennent, avec de plus hauts frais. Cela annulera la transaction. On parle de RBF - Replace By Fee.",
"cancel_no": "Cette transaction n'est pas remplaçable",
"cancel_title": "Annuler cette transaction (RBF)",
"confirmations_lowercase": "{confirmations} confirmations",
"transaction_id": "ID de transaction",
"note": "Note",
"expand_note": "Développer la note",
"block_explorer_link": "Lien vers l'explorateur de blocs",
"cpfp_create": "Créer",
"cpfp_exp": "Nous allons créer une autre transaction qui dépense votre transaction non-confirmée. Les frais totaux seront supérieurs aux frais de la transaction originale, donc cela devrait être miné plus rapidement. On parle de CPFP - Child Pays For Parent.",
"cpfp_no_bump": "Cette transaction n'est pas propulsable",
@ -345,7 +351,7 @@
"details_inputs": "Inputs",
"details_outputs": "Outputs",
"details_received": "Reçu",
"transaction_note_saved":"La note de transaction a été enregistrée avec succès.",
"transaction_note_saved": "La note de transaction a été enregistrée avec succès.",
"details_show_in_block_explorer": "Afficher dans le \"block explorer\"",
"details_title": "Transaction",
"details_to": "À",
@ -359,7 +365,7 @@
"status_bump": "Frais de propulsion",
"status_cancel": "Annuler la transaction",
"transactions_count": "Nombre de transactions",
"txid": "Txid",
"txid": "ID de transaction",
"updating": "Chargement..."
},
"wallets": {
@ -411,7 +417,7 @@
"export_title": "export du portefeuille",
"import_do_import": "Importer",
"import_error": "Échec de l'import. Merci, de vérifier que les données saisies sont valides.",
"import_explanation": "Écrivez ici vos mnémonique, clés privés, WIF ou tout simplement ce que vous avez. Bluewallet fera de son mieux pour détecter automatiquement le bon format. Si c'est une clé publique, nous créerons une portefeuille en lecture seul. ",
"import_explanation": "Entrez ici votre mnémonique, clé privée, WIF, ou quoi que ce soit que vous ayez. BlueWallet fera de son mieux pour deviner le bon format et importer votre portefeuille",
"import_file": "Importer le fichier",
"import_imported": "Importé",
"import_placeholder_fail": "Importation de portefeuille",
@ -424,7 +430,7 @@
"list_create_a_wallet_text": "Cest gratuit et vous pouvez en créer \nautant que vous voulez.",
"list_empty_txs1": "Vos transactions apparaîtront ici,",
"list_empty_txs1_lightning": "Un portefeuille Lightning devrait être utilisé pour les transactions quotidiennes. Les frais sont très bas et la vitesse est étourdissante.",
"list_empty_txs2": "Aucune pour le moment",
"list_empty_txs2": "Commencez avec votre portefeuille.",
"list_empty_txs2_lightning": "\nPour commencer à l'utiliser taper sur \"Gérer les fonds\" et alimentez votre solde.",
"list_header": "Un portefeuille (wallet) représente une paire de clés, une privée et une publique que vous pouvez partager pour recevoir des fonds. ",
"list_import_error": "Une erreur est survenue lors de la tentative d'import du portefeuille.",
@ -468,7 +474,7 @@
"share": "Partager",
"view": "Vue",
"manage_keys": "Gérer les clés",
"how_many_signatures_can_bluewallet_make": "Combien de signature peut faire bluewallet",
"how_many_signatures_can_bluewallet_make": "Combien de signatures BlueWallet peut-il faire",
"signatures_required_to_spend": "Signatures necessaires {number}",
"signatures_we_can_make": "peut faire {number}",
"scan_or_import_file": "Scanner ou importer fichier",

View file

@ -1,13 +0,0 @@
export class BitcoinTransaction {
/**
*
* @param address
* @param amount {number}
* @param amountSats {integer} satoshi
*/
constructor(address = '', amount, amountSats) {
this.address = address;
this.amount = amount;
this.amountSats = amountSats;
}
}

52
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "bluewallet",
"version": "6.0.6",
"version": "6.0.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -5337,6 +5337,11 @@
"deep-assign": "^3.0.0"
}
},
"@react-native-clipboard/clipboard": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.7.0.tgz",
"integrity": "sha512-i5dJgR+wM8Om+hFEB/PqNb65/x5WxpaZG+UjEBX2/gmmIrmAWI72tI9rVL1gjPA9RWNpdpzvp+ioGjpdl7MyWQ=="
},
"@react-native-community/blur": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@react-native-community/blur/-/blur-3.6.0.tgz",
@ -5682,11 +5687,6 @@
"resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-4.10.1.tgz",
"integrity": "sha512-ael2f1onoPF3vF7YqHGWy7NnafzGu+yp88BbFbP0ydoCP2xGSUzmZVw0zakPTC040Id+JQ9WeFczujMkDy6jYQ=="
},
"@react-native-community/clipboard": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@react-native-community/clipboard/-/clipboard-1.5.1.tgz",
"integrity": "sha512-AHAmrkLEH5UtPaDiRqoULERHh3oNv7Dgs0bTC0hO5Z2GdNokAMPT5w8ci8aMcRemcwbtdHjxChgtjbeA38GBdA=="
},
"@react-native-community/eslint-config": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/eslint-config/-/eslint-config-2.0.0.tgz",
@ -7343,10 +7343,12 @@
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"bc-bech32": {
"version": "file:blue_modules/bc-bech32"
"version": "file:blue_modules/bc-bech32",
"integrity": "sha512-lwAn5R4LUhcnyrZgNx3YdDPr5+nseM4kARANcv8i0YOMtnPJRTF7B7TZzS3DYgC6tff/aR2W/3jGoY/SJMs6MA=="
},
"bc-ur": {
"version": "file:blue_modules/bc-ur"
"version": "file:blue_modules/bc-ur",
"integrity": "sha512-k5jZLNgiCMQH5d/4lwsa6DJjH12vzdTEr9qVH1y9UPzJW32Ga1u8iC0KDAqtYnkvh8NR4DW8Fco6D2hphHZLzg=="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
@ -8730,9 +8732,9 @@
"dev": true
},
"detox": {
"version": "18.2.2",
"resolved": "https://registry.npmjs.org/detox/-/detox-18.2.2.tgz",
"integrity": "sha512-+4foyz7HraKWAHavkmN4QKaWVUcWdqdnI5ftak1ilIloZaZPGHuIe1ymRC2xoWtpdIpvW6mRJkhm7TeJrZW9HA==",
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/detox/-/detox-18.3.1.tgz",
"integrity": "sha512-eYvBTkJ0bvBcaWxubQBhRk+sT0Yd21npebd/s25BFrfB+8Ts4ctGASXh2uqlHkvCzUIDzRTEgFLu9I5k3g89Fw==",
"requires": {
"bunyan": "^1.8.12",
"bunyan-debug-stream": "^1.1.0",
@ -8851,9 +8853,9 @@
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg=="
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -8898,9 +8900,9 @@
}
},
"yargs-parser": {
"version": "20.2.4",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA=="
"version": "20.2.6",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.6.tgz",
"integrity": "sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA=="
}
}
},
@ -18388,9 +18390,9 @@
"from": "react-native-blue-crypto@git+https://github.com/Overtorment/react-native-blue-crypto.git"
},
"react-native-camera": {
"version": "3.42.0",
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.42.0.tgz",
"integrity": "sha512-DFsZeRy9TKP/pGef5iLX1AWxP9eAnlbGcA76fEoFXse6EP56sdgjYe+wudJsGZ//arGrYBqjq6wog13HMsJaoQ==",
"version": "3.42.2",
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.42.2.tgz",
"integrity": "sha512-sqeVZiHP3hDdSVlVTM62Nry9+Enff06IqicK2bth+NKWPccwOHw4QXLMf7M5rpGFAIfbSGCcy0U1r+biv6R6rw==",
"requires": {
"prop-types": "^15.6.2"
}
@ -18446,11 +18448,12 @@
}
},
"react-native-gesture-handler": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.9.0.tgz",
"integrity": "sha512-fkkNeWDBzDdwDxDcxtYbrb9T1g0PLgT1AxBs2iO/p7uEbDbC6mIoL/NzuOnKNEBHcd0lpLoJuNmIfdmucEON5g==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.10.0.tgz",
"integrity": "sha512-ezqA2Hyy6pFF7uxRZA8TeRUZs4zMo5DQQjo0UfFVJyAqjMraDkbz+t/uCfyBowrnOyOiNAhPHB85k6vgPvlZ+g==",
"requires": {
"@egjs/hammerjs": "^2.0.17",
"@types/hammerjs": "^2.0.38",
"fbjs": "^3.0.0",
"hoist-non-react-statics": "^3.3.0",
"invariant": "^2.2.4",
@ -19557,7 +19560,8 @@
}
},
"scryptsy": {
"version": "file:blue_modules/scryptsy"
"version": "file:blue_modules/scryptsy",
"integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w=="
},
"secp256k1": {
"version": "3.8.0",

View file

@ -1,6 +1,6 @@
{
"name": "bluewallet",
"version": "6.0.6",
"version": "6.0.7",
"license": "MIT",
"repository": {
"type": "git",
@ -48,7 +48,7 @@
"e2e:debug-test": "detox test -c android.emu.debug",
"e2e:debug": "(test -f android/app/build/outputs/apk/debug/app-debug.apk && test -f android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk) || npm run e2e:debug-build; npm run e2e:debug-test",
"e2e:release-build": "npx detox build -c android.emu.release",
"e2e:release-test": "detox test -c android.emu.release --record-videos all --take-screenshots all --headless",
"e2e:release-test": "detox test -c android.emu.release --record-videos all --take-screenshots all --headless --loglevel trace",
"lint": "eslint *.js screen/**/*.js blue_modules/*.js class/**/*.js models/ loc/ tests/**/*.js components/**/*.js",
"lint:fix": "npm run lint -- --fix",
"lint:quickfix": "git status --porcelain | grep -v '\\.json' | grep '\\.js' --color=never | awk '{print $2}' | xargs eslint --fix; exit 0",
@ -72,8 +72,8 @@
"dependencies": {
"@babel/preset-env": "7.12.1",
"@react-native-async-storage/async-storage": "1.13.4",
"@react-native-clipboard/clipboard": "1.7.0",
"@react-native-community/blur": "3.6.0",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/masked-view": "0.1.10",
"@react-native-community/push-notification-ios": "1.8.0",
"@react-native-community/slider": "3.0.3",
@ -100,7 +100,7 @@
"coinselect": "3.1.12",
"crypto-js": "3.1.9-1",
"dayjs": "1.10.4",
"detox": "18.2.2",
"detox": "18.3.1",
"ecurve": "1.0.6",
"electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git#f9a827e724a5a2e578fdfdb483f83793af55b030",
"electrum-mnemonic": "2.0.0",
@ -125,14 +125,14 @@
"react-localization": "1.0.15",
"react-native": "0.63.3",
"react-native-blue-crypto": "git+https://github.com/Overtorment/react-native-blue-crypto.git",
"react-native-camera": "3.42.0",
"react-native-camera": "3.42.2",
"react-native-default-preference": "1.4.3",
"react-native-device-info": "8.0.1",
"react-native-document-picker": "git+https://github.com/BlueWallet/react-native-document-picker.git#3684d4fcc2bc0b47c32be39024e4796004c3e428",
"react-native-elements": "2.3.2",
"react-native-fingerprint-scanner": "git+https://github.com/BlueWallet/react-native-fingerprint-scanner.git#ce644673681716335d786727bab998f7e632ab5e",
"react-native-fs": "2.16.6",
"react-native-gesture-handler": "1.9.0",
"react-native-gesture-handler": "1.10.0",
"react-native-handoff": "git+https://github.com/marcosrdz/react-native-handoff.git#f5becc63f3e36bf2da1ed1fc60fc690323e73602",
"react-native-haptic-feedback": "1.11.0",
"react-native-idle-timer": "git+https://github.com/BlueWallet/react-native-idle-timer.git#8587876d68ab5920e79619726aeca9e672beaf2b",

View file

@ -18,14 +18,9 @@ import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { Icon } from 'react-native-elements';
import { useFocusEffect, useNavigation, useRoute, useTheme } from '@react-navigation/native';
import {
BlueAlertWalletExportReminder,
BlueBitcoinAmount,
BlueButton,
BlueDismissKeyboardInputAccessory,
BlueLoading,
} from '../../BlueComponents';
import { BlueAlertWalletExportReminder, BlueButton, BlueDismissKeyboardInputAccessory, BlueLoading } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import AmountInput from '../../components/AmountInput';
import * as NavigationService from '../../NavigationService';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
@ -163,7 +158,7 @@ const LNDCreateInvoice = () => {
break;
case BitcoinUnit.LOCAL_CURRENCY:
// trying to fetch cached sat equivalent for this fiat amount
invoiceAmount = BlueBitcoinAmount.getCachedSatoshis(invoiceAmount) || currency.btcToSatoshi(currency.fiatToBTC(invoiceAmount));
invoiceAmount = AmountInput.getCachedSatoshis(invoiceAmount) || currency.btcToSatoshi(currency.fiatToBTC(invoiceAmount));
break;
}
@ -260,7 +255,7 @@ const LNDCreateInvoice = () => {
break;
case BitcoinUnit.LOCAL_CURRENCY:
amount = formatBalancePlain(amount, BitcoinUnit.LOCAL_CURRENCY);
BlueBitcoinAmount.setCachedSatoshis(amount, sats);
AmountInput.setCachedSatoshis(amount, sats);
break;
}
@ -362,7 +357,7 @@ const LNDCreateInvoice = () => {
<StatusBar barStyle="light-content" />
<View style={[styles.amount, styleHooks.amount]}>
<KeyboardAvoidingView enabled={!Platform.isPad} behavior="position">
<BlueBitcoinAmount
<AmountInput
isLoading={isLoading}
amount={amount}
onAmountUnitChange={setUnit}

View file

@ -6,9 +6,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import { Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Icon } from 'react-native-elements';
import navigationStyle from '../../components/navigationStyle';
import {
BlueBitcoinAmount,
BlueButton,
BlueCard,
BlueDismissKeyboardInputAccessory,
@ -17,6 +15,8 @@ import {
BlueText,
SafeBlueArea,
} from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import AmountInput from '../../components/AmountInput';
import { BlueCurrentTheme } from '../../components/themes';
import Lnurl from '../../class/lnurl';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
@ -160,7 +160,7 @@ export default class LnurlPay extends Component {
<SafeBlueArea style={styles.root}>
<ScrollView>
<BlueCard>
<BlueBitcoinAmount
<AmountInput
isLoading={this.state.isLoading}
amount={this.state.amount.toString()}
onAmountUnitChange={unit => {

View file

@ -15,16 +15,10 @@ import { Icon } from 'react-native-elements';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { useFocusEffect, useNavigation, useRoute, useTheme } from '@react-navigation/native';
import {
BlueButton,
SafeBlueArea,
BlueCard,
BlueDismissKeyboardInputAccessory,
BlueAddressInput,
BlueBitcoinAmount,
BlueLoading,
} from '../../BlueComponents';
import { BlueButton, BlueCard, BlueDismissKeyboardInputAccessory, BlueLoading, SafeBlueArea } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import AddressInput from '../../components/AddressInput';
import AmountInput from '../../components/AmountInput';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
import Lnurl from '../../class/lnurl';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
@ -296,7 +290,7 @@ const ScanLndInvoice = () => {
<ScrollView contentContainerStyle={styles.scroll}>
<KeyboardAvoidingView enabled behavior="position" keyboardVerticalOffset={20}>
<View style={styles.scrollMargin}>
<BlueBitcoinAmount
<AmountInput
pointerEvents={isAmountInitiallyEmpty ? 'auto' : 'none'}
isLoading={isLoading}
amount={amount}
@ -309,7 +303,7 @@ const ScanLndInvoice = () => {
</View>
<BlueCard>
<BlueAddressInput
<AddressInput
onChangeText={text => {
text = text.trim();
processTextForInvoice(text);

View file

@ -21,7 +21,6 @@ import {
SecondButton,
BlueButtonLink,
is,
BlueBitcoinAmount,
BlueText,
BlueSpacing20,
BlueAlertWalletExportReminder,
@ -31,6 +30,7 @@ import BottomModal from '../../components/BottomModal';
import Privacy from '../../blue_modules/Privacy';
import { Chain, BitcoinUnit } from '../../models/bitcoinUnits';
import HandoffComponent from '../../components/handoff';
import AmountInput from '../../components/AmountInput';
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -297,9 +297,9 @@ const ReceiveDetails = () => {
amount = currency.satoshiToBTC(customAmount);
break;
case BitcoinUnit.LOCAL_CURRENCY:
if (BlueBitcoinAmount.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]) {
if (AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]) {
// cache hit! we reuse old value that supposedly doesnt have rounding errors
amount = currency.satoshiToBTC(BlueBitcoinAmount.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]);
amount = currency.satoshiToBTC(AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]);
} else {
amount = currency.fiatToBTC(customAmount);
}
@ -314,12 +314,7 @@ const ReceiveDetails = () => {
<BottomModal isVisible={isCustomModalVisible} onClose={dismissCustomAmountModal}>
<KeyboardAvoidingView enabled={!Platform.isPad} behavior={Platform.OS === 'ios' ? 'position' : null}>
<View style={styles.modalContent}>
<BlueBitcoinAmount
unit={customUnit}
amount={customAmount || ''}
onChangeText={setCustomAmount}
onAmountUnitChange={setCustomUnit}
/>
<AmountInput unit={customUnit} amount={customAmount || ''} onChangeText={setCustomAmount} onAmountUnitChange={setCustomUnit} />
<View style={styles.customAmount}>
<TextInput
onChangeText={setCustomLabel}

View file

@ -16,7 +16,7 @@ import {
PermissionsAndroid,
Alert,
} from 'react-native';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import { Icon } from 'react-native-elements';
import Share from 'react-native-share';
import RNFS from 'react-native-fs';

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@ import {
Alert,
findNodeHandle,
} from 'react-native';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import Share from 'react-native-share';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import DocumentPicker from 'react-native-document-picker';

View file

@ -12,7 +12,7 @@ import {
StyleSheet,
KeyboardAvoidingView,
} from 'react-native';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import { Text } from 'react-native-elements';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

View file

@ -7,7 +7,7 @@ import navigationStyle from '../../components/navigationStyle';
import HandoffComponent from '../../components/handoff';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import ToolTipMenu from '../../components/TooltipMenu';
const dayjs = require('dayjs');

View file

@ -19,7 +19,7 @@ import { Icon } from 'react-native-elements';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import { getSystemName } from 'react-native-device-info';
import QRCode from 'react-native-qrcode-svg';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import showPopupMenu from 'react-native-popup-menu-android';
import ToolTip from 'react-native-tooltip';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

View file

@ -22,13 +22,12 @@ import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { PlaceholderWallet } from '../../class';
import WalletImport from '../../class/wallet-import';
import ActionSheet from '../ActionSheet';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import loc from '../../loc';
import { FContainer, FButton } from '../../components/FloatButtons';
import { isTablet } from 'react-native-device-info';
import { useFocusEffect, useNavigation, useRoute, useTheme } from '@react-navigation/native';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import { isCatalyst, isMacCatalina } from '../../blue_modules/environment';
import { isCatalyst, isMacCatalina, isTablet } from '../../blue_modules/environment';
const A = require('../../blue_modules/analytics');
const fs = require('../../blue_modules/fs');
@ -46,7 +45,7 @@ const WalletsList = () => {
const [isLoading, setIsLoading] = useState(false);
const [itemWidth, setItemWidth] = useState(width * 0.82 > 375 ? 375 : width * 0.82);
const [isLargeScreen, setIsLargeScreen] = useState(
Platform.OS === 'android' ? isTablet() : width >= Dimensions.get('screen').width / 2 && isTablet(),
Platform.OS === 'android' ? isTablet() : width >= Dimensions.get('screen').width / 2 && (isTablet() || isCatalyst),
);
const [carouselData, setCarouselData] = useState([]);
const dataSource = getTransactions(null, 10);
@ -433,7 +432,7 @@ const WalletsList = () => {
};
const onLayout = _e => {
setIsLargeScreen(Platform.OS === 'android' ? isTablet() : width >= Dimensions.get('screen').width / 2 && isTablet());
setIsLargeScreen(Platform.OS === 'android' ? isTablet() : width >= Dimensions.get('screen').width / 2 && (isTablet() || isCatalyst));
setItemWidth(width * 0.82 > 375 ? 375 : width * 0.82);
};

View file

@ -20,7 +20,7 @@ import {
View,
} from 'react-native';
import { launchImageLibrary } from 'react-native-image-picker';
import Clipboard from '@react-native-community/clipboard';
import Clipboard from '@react-native-clipboard/clipboard';
import { Icon } from 'react-native-elements';
import { useRoute, useNavigation, useTheme, useFocusEffect } from '@react-navigation/native';
import { Chain } from '../../models/bitcoinUnits';