mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-20 14:05:27 +01:00
FIX: syncup with master, fix eslint errors
This commit is contained in:
parent
7d47682e0b
commit
1676c79185
26 changed files with 1043 additions and 536 deletions
|
@ -394,70 +394,83 @@ export const BlueAlertWalletExportReminder = ({ onSuccess = () => {}, onFailure
|
|||
);
|
||||
};
|
||||
|
||||
export const BlueNavigationStyle = (navigation, withNavigationCloseButton = false, customCloseButtonFunction = undefined) => ({
|
||||
headerStyle: {
|
||||
backgroundColor: BlueApp.settings.brandingColor,
|
||||
borderBottomWidth: 0,
|
||||
elevation: 0,
|
||||
shadowOffset: { height: 0, width: 0 },
|
||||
},
|
||||
headerTitleStyle: {
|
||||
fontWeight: '600',
|
||||
color: BlueApp.settings.foregroundColor,
|
||||
},
|
||||
headerTintColor: BlueApp.settings.foregroundColor,
|
||||
headerRight: withNavigationCloseButton
|
||||
? () => (
|
||||
export const BlueNavigationStyle = (navigation, withNavigationCloseButton = false, customCloseButtonFunction = undefined) => {
|
||||
let headerRight;
|
||||
if (withNavigationCloseButton) {
|
||||
headerRight = () => (
|
||||
<TouchableOpacity
|
||||
style={{ width: 40, height: 40, padding: 14 }}
|
||||
onPress={
|
||||
customCloseButtonFunction === undefined
|
||||
? () => {
|
||||
Keyboard.dismiss();
|
||||
navigation.goBack(null);
|
||||
}
|
||||
: customCloseButtonFunction
|
||||
}
|
||||
>
|
||||
<Image style={{ alignSelf: 'center' }} source={require('./img/close.png')} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
: null,
|
||||
// headerBackTitle: null,
|
||||
headerBackTitleVisible: false,
|
||||
});
|
||||
style={{ width: 40, height: 40, padding: 14 }}
|
||||
onPress={
|
||||
customCloseButtonFunction === undefined
|
||||
? () => {
|
||||
Keyboard.dismiss();
|
||||
navigation.goBack(null);
|
||||
}
|
||||
: customCloseButtonFunction
|
||||
}
|
||||
>
|
||||
<Image style={{ alignSelf: 'center' }} source={require('./img/close.png')} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
} else {
|
||||
headerRight = null;
|
||||
}
|
||||
|
||||
export const BlueCreateTxNavigationStyle = (navigation, withAdvancedOptionsMenuButton = false, advancedOptionsMenuButtonAction) => ({
|
||||
headerStyle: {
|
||||
backgroundColor: BlueApp.settings.brandingColor,
|
||||
borderBottomWidth: 0,
|
||||
elevation: 0,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
fontWeight: '600',
|
||||
color: BlueApp.settings.foregroundColor,
|
||||
},
|
||||
headerTintColor: BlueApp.settings.foregroundColor,
|
||||
headerLeft: () => (
|
||||
<TouchableOpacity
|
||||
style={{ minWwidth: 40, height: 40, padding: 14 }}
|
||||
onPress={() => {
|
||||
Keyboard.dismiss();
|
||||
navigation.goBack(null);
|
||||
}}
|
||||
>
|
||||
<Image style={{ alignSelf: 'center' }} source={require('./img/close.png')} />
|
||||
</TouchableOpacity>
|
||||
),
|
||||
headerRight: withAdvancedOptionsMenuButton
|
||||
? () => (
|
||||
return {
|
||||
headerStyle: {
|
||||
backgroundColor: BlueApp.settings.brandingColor,
|
||||
borderBottomWidth: 0,
|
||||
elevation: 0,
|
||||
shadowOffset: { height: 0, width: 0 },
|
||||
},
|
||||
headerTitleStyle: {
|
||||
fontWeight: '600',
|
||||
color: BlueApp.settings.foregroundColor,
|
||||
},
|
||||
headerTintColor: BlueApp.settings.foregroundColor,
|
||||
headerRight,
|
||||
// headerBackTitle: null,
|
||||
headerBackTitleVisible: false,
|
||||
};
|
||||
};
|
||||
|
||||
export const BlueCreateTxNavigationStyle = (navigation, withAdvancedOptionsMenuButton = false, advancedOptionsMenuButtonAction) => {
|
||||
let headerRight;
|
||||
if (withAdvancedOptionsMenuButton) {
|
||||
headerRight = () => (
|
||||
<TouchableOpacity style={{ minWidth: 40, height: 40, padding: 14 }} onPress={advancedOptionsMenuButtonAction}>
|
||||
<Icon size={22} name="kebab-horizontal" type="octicon" color={BlueApp.settings.foregroundColor} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
: null,
|
||||
headerBackTitle: null,
|
||||
});
|
||||
<Icon size={22} name="kebab-horizontal" type="octicon" color={BlueApp.settings.foregroundColor} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
} else {
|
||||
headerRight = null;
|
||||
}
|
||||
return {
|
||||
headerStyle: {
|
||||
backgroundColor: BlueApp.settings.brandingColor,
|
||||
borderBottomWidth: 0,
|
||||
elevation: 0,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
fontWeight: '600',
|
||||
color: BlueApp.settings.foregroundColor,
|
||||
},
|
||||
headerTintColor: BlueApp.settings.foregroundColor,
|
||||
headerLeft: () => (
|
||||
<TouchableOpacity
|
||||
style={{ minWwidth: 40, height: 40, padding: 14 }}
|
||||
onPress={() => {
|
||||
Keyboard.dismiss();
|
||||
navigation.goBack(null);
|
||||
}}
|
||||
>
|
||||
<Image style={{ alignSelf: 'center' }} source={require('./img/close.png')} />
|
||||
</TouchableOpacity>
|
||||
),
|
||||
headerRight,
|
||||
headerBackTitle: null,
|
||||
};
|
||||
};
|
||||
|
||||
export const BluePrivateBalance = () => {
|
||||
return Platform.select({
|
||||
|
@ -1368,8 +1381,7 @@ export class NewWalletPanel extends Component {
|
|||
render() {
|
||||
return (
|
||||
<TouchableOpacity testID="CreateAWallet" {...this.props} onPress={this.props.onPress} style={{ marginVertical: 17 }}>
|
||||
<LinearGradient
|
||||
colors={WalletGradient.createWallet}
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 24,
|
||||
paddingVertical: 16,
|
||||
|
@ -1377,6 +1389,7 @@ export class NewWalletPanel extends Component {
|
|||
minHeight: Platform.OS === 'ios' ? 164 : 181,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start',
|
||||
backgroundColor: WalletGradient.createWallet,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
|
@ -1409,7 +1422,7 @@ export class NewWalletPanel extends Component {
|
|||
<View style={{ marginTop: 12, backgroundColor: '#007AFF', paddingHorizontal: 32, paddingVertical: 12, borderRadius: 8 }}>
|
||||
<Text style={{ color: BlueApp.settings.brandingColor, fontWeight: '500' }}>{loc.wallets.list.create_a_button}</Text>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
@ -1784,223 +1797,250 @@ export class BlueListTransactionItem extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
const WalletCarouselItem = ({ item, index, onPress, handleLongPress }) => {
|
||||
let scaleValue = new Animated.Value(1.0);
|
||||
|
||||
const onPressedIn = () => {
|
||||
let props = { duration: 50 };
|
||||
if (Platform.OS === 'android') {
|
||||
props['useNativeDriver'] = true;
|
||||
}
|
||||
|
||||
props.toValue = 0.9;
|
||||
Animated.spring(scaleValue, props).start();
|
||||
};
|
||||
const onPressedOut = () => {
|
||||
let props = { duration: 50 };
|
||||
if (Platform.OS === 'android') {
|
||||
props['useNativeDriver'] = true;
|
||||
}
|
||||
|
||||
props.toValue = 1.0;
|
||||
Animated.spring(scaleValue, props).start();
|
||||
};
|
||||
|
||||
if (!item) {
|
||||
return (
|
||||
<NewWalletPanel
|
||||
onPress={() => {
|
||||
onPressedOut();
|
||||
onPress(index);
|
||||
onPressedOut();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (item.type === PlaceholderWallet.type) {
|
||||
return (
|
||||
<Animated.View
|
||||
style={{ paddingRight: 10, marginVertical: 17, transform: [{ scale: scaleValue }] }}
|
||||
shadowOpacity={40 / 100}
|
||||
shadowOffset={{ width: 0, height: 0 }}
|
||||
shadowRadius={5}
|
||||
>
|
||||
<TouchableWithoutFeedback
|
||||
onPressIn={item.getIsFailure() ? onPressedIn : null}
|
||||
onPressOut={item.getIsFailure() ? onPressedOut : null}
|
||||
onPress={() => {
|
||||
if (item.getIsFailure()) {
|
||||
onPressedOut();
|
||||
onPress(index);
|
||||
onPressedOut();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<LinearGradient
|
||||
shadowColor={BlueApp.settings.shadowColor}
|
||||
colors={WalletGradient.gradientsFor(item.type)}
|
||||
style={{
|
||||
padding: 15,
|
||||
borderRadius: 10,
|
||||
minHeight: 164,
|
||||
elevation: 5,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={require('./img/btc-shape.png')}
|
||||
style={{
|
||||
width: 99,
|
||||
height: 94,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
<Text style={{ backgroundColor: 'transparent' }} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 19,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{item.getLabel()}
|
||||
</Text>
|
||||
{item.getIsFailure() ? (
|
||||
<Text
|
||||
numberOfLines={0}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 19,
|
||||
marginTop: 40,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
An error was encountered when attempting to import this wallet.
|
||||
</Text>
|
||||
) : (
|
||||
<ActivityIndicator style={{ marginTop: 40 }} />
|
||||
)}
|
||||
</LinearGradient>
|
||||
</TouchableWithoutFeedback>
|
||||
</Animated.View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Animated.View
|
||||
style={{ paddingRight: 10, marginVertical: 17, transform: [{ scale: scaleValue }] }}
|
||||
shadowOpacity={40 / 100}
|
||||
shadowOffset={{ width: 0, height: 0 }}
|
||||
shadowRadius={5}
|
||||
>
|
||||
<TouchableWithoutFeedback
|
||||
testID={item.getLabel()}
|
||||
onPressIn={onPressedIn}
|
||||
onPressOut={onPressedOut}
|
||||
onLongPress={handleLongPress}
|
||||
onPress={() => {
|
||||
onPressedOut();
|
||||
onPress(index);
|
||||
onPressedOut();
|
||||
}}
|
||||
>
|
||||
<LinearGradient
|
||||
shadowColor={BlueApp.settings.shadowColor}
|
||||
colors={WalletGradient.gradientsFor(item.type)}
|
||||
style={{
|
||||
padding: 15,
|
||||
borderRadius: 10,
|
||||
minHeight: 164,
|
||||
elevation: 5,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={(LightningCustodianWallet.type === item.type && require('./img/lnd-shape.png')) || require('./img/btc-shape.png')}
|
||||
style={{
|
||||
width: 99,
|
||||
height: 94,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
<Text style={{ backgroundColor: 'transparent' }} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 19,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{item.getLabel()}
|
||||
</Text>
|
||||
{item.hideBalance ? (
|
||||
<BluePrivateBalance />
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
adjustsFontSizeToFit
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 36,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit(), true)}
|
||||
</Text>
|
||||
)}
|
||||
<Text style={{ backgroundColor: 'transparent' }} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 13,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{loc.wallets.list.latest_transaction}
|
||||
</Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{loc.transactionTimeToReadable(item.getLatestTransactionTime())}
|
||||
</Text>
|
||||
</LinearGradient>
|
||||
</TouchableWithoutFeedback>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const sliderWidth = width * 1;
|
||||
const itemWidth = width * 0.82;
|
||||
const itemWidth = width * 0.82 > 375 ? 375 : width * 0.82;
|
||||
const sliderHeight = 190;
|
||||
|
||||
export class WalletsCarousel extends Component {
|
||||
walletsCarousel = React.createRef();
|
||||
|
||||
state = { isLoading: true };
|
||||
|
||||
_renderItem = ({ item, index }) => {
|
||||
let scaleValue = new Animated.Value(1.0);
|
||||
let props = { duration: 50 };
|
||||
if (Platform.OS === 'android') {
|
||||
props['useNativeDriver'] = true;
|
||||
}
|
||||
this.onPressedIn = () => {
|
||||
props.toValue = 0.9;
|
||||
Animated.spring(scaleValue, props).start();
|
||||
};
|
||||
this.onPressedOut = () => {
|
||||
props.toValue = 1.0;
|
||||
Animated.spring(scaleValue, props).start();
|
||||
};
|
||||
|
||||
if (!item) {
|
||||
return (
|
||||
<NewWalletPanel
|
||||
onPress={() => {
|
||||
this.onPressedOut();
|
||||
this.props.onPress(index);
|
||||
this.onPressedOut();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (item.type === PlaceholderWallet.type) {
|
||||
return (
|
||||
<Animated.View
|
||||
style={{ paddingRight: 10, marginVertical: 17, transform: [{ scale: scaleValue }] }}
|
||||
shadowOpacity={40 / 100}
|
||||
shadowOffset={{ width: 0, height: 0 }}
|
||||
shadowRadius={5}
|
||||
>
|
||||
<TouchableWithoutFeedback
|
||||
onPressIn={item.getIsFailure() ? this.onPressedIn : null}
|
||||
onPressOut={item.getIsFailure() ? this.onPressedOut : null}
|
||||
onPress={() => {
|
||||
if (item.getIsFailure()) {
|
||||
this.onPressedOut();
|
||||
this.props.onPress(index);
|
||||
this.onPressedOut();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<LinearGradient
|
||||
shadowColor={BlueApp.settings.shadowColor}
|
||||
colors={WalletGradient.gradientsFor(item.type)}
|
||||
style={{
|
||||
padding: 15,
|
||||
borderRadius: 10,
|
||||
minHeight: 164,
|
||||
elevation: 5,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={require('./img/btc-shape.png')}
|
||||
style={{
|
||||
width: 99,
|
||||
height: 94,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
<Text style={{ backgroundColor: 'transparent' }} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 19,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{item.getLabel()}
|
||||
</Text>
|
||||
{item.getIsFailure() ? (
|
||||
<Text
|
||||
numberOfLines={0}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 19,
|
||||
marginTop: 40,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
An error was encountered when attempting to import this wallet.
|
||||
</Text>
|
||||
) : (
|
||||
<ActivityIndicator style={{ marginTop: 40 }} />
|
||||
)}
|
||||
</LinearGradient>
|
||||
</TouchableWithoutFeedback>
|
||||
</Animated.View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Animated.View
|
||||
style={{ paddingRight: 10, marginVertical: 17, transform: [{ scale: scaleValue }] }}
|
||||
shadowOpacity={40 / 100}
|
||||
shadowOffset={{ width: 0, height: 0 }}
|
||||
shadowRadius={5}
|
||||
>
|
||||
<TouchableWithoutFeedback
|
||||
testID={item.getLabel()}
|
||||
onPressIn={this.onPressedIn}
|
||||
onPressOut={this.onPressedOut}
|
||||
onLongPress={this.props.handleLongPress}
|
||||
onPress={() => {
|
||||
this.onPressedOut();
|
||||
this.props.onPress(index);
|
||||
this.onPressedOut();
|
||||
}}
|
||||
>
|
||||
<LinearGradient
|
||||
shadowColor={BlueApp.settings.shadowColor}
|
||||
colors={WalletGradient.gradientsFor(item.type)}
|
||||
style={{
|
||||
padding: 15,
|
||||
borderRadius: 10,
|
||||
minHeight: 164,
|
||||
elevation: 5,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={(LightningCustodianWallet.type === item.type && require('./img/lnd-shape.png')) || require('./img/btc-shape.png')}
|
||||
style={{
|
||||
width: 99,
|
||||
height: 94,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
<Text style={{ backgroundColor: 'transparent' }} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 19,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{item.getLabel()}
|
||||
</Text>
|
||||
{item.hideBalance ? (
|
||||
<BluePrivateBalance />
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
adjustsFontSizeToFit
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 36,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit(), true)}
|
||||
</Text>
|
||||
)}
|
||||
<Text style={{ backgroundColor: 'transparent' }} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 13,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{loc.wallets.list.latest_transaction}
|
||||
</Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
color: BlueApp.settings.inverseForegroundColor,
|
||||
}}
|
||||
>
|
||||
{loc.transactionTimeToReadable(item.getLatestTransactionTime())}
|
||||
</Text>
|
||||
</LinearGradient>
|
||||
</TouchableWithoutFeedback>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
return <WalletCarouselItem item={item} index={index} handleLongPress={this.props.handleLongPress} onPress={this.props.onPress} />;
|
||||
};
|
||||
|
||||
snapToItem = item => {
|
||||
this.walletsCarousel.current.snapToItem(item);
|
||||
};
|
||||
|
||||
onLayout = () => {
|
||||
this.setState({ isLoading: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Carousel
|
||||
{...this.props}
|
||||
ref={this.walletsCarousel}
|
||||
renderItem={this._renderItem}
|
||||
sliderWidth={sliderWidth}
|
||||
sliderHeight={sliderHeight}
|
||||
itemWidth={itemWidth}
|
||||
inactiveSlideScale={1}
|
||||
inactiveSlideOpacity={0.7}
|
||||
contentContainerCustomStyle={{ left: -20 }}
|
||||
onSnapToItem={this.onSnapToItem}
|
||||
/>
|
||||
<>
|
||||
{this.state.isLoading && (
|
||||
<View
|
||||
style={{ paddingVertical: sliderHeight / 2, paddingHorizontal: sliderWidth / 2, position: 'absolute', alignItems: 'center' }}
|
||||
>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
)}
|
||||
<Carousel
|
||||
{...this.props}
|
||||
ref={this.walletsCarousel}
|
||||
renderItem={this._renderItem}
|
||||
sliderWidth={sliderWidth}
|
||||
sliderHeight={sliderHeight}
|
||||
itemWidth={itemWidth}
|
||||
inactiveSlideScale={1}
|
||||
inactiveSlideOpacity={0.7}
|
||||
initialNumToRender={4}
|
||||
onLayout={this.onLayout}
|
||||
contentContainerCustomStyle={{ left: -20 }}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -339,7 +339,7 @@ module.exports.multiGetHistoryByAddress = async function(addresses, batchsize) {
|
|||
};
|
||||
|
||||
module.exports.multiGetTransactionByTxid = async function(txids, batchsize, verbose) {
|
||||
batchsize = batchsize || 49;
|
||||
batchsize = batchsize || 45;
|
||||
// this value is fine-tuned so althrough wallets in test suite will occasionally
|
||||
// throw 'response too large (over 1,000,000 bytes', test suite will pass
|
||||
verbose = verbose !== false;
|
||||
|
|
|
@ -39,6 +39,7 @@ import RBFBumpFee from './screen/transactions/RBFBumpFee';
|
|||
import RBFCancel from './screen/transactions/RBFCancel';
|
||||
|
||||
import ReceiveDetails from './screen/receive/details';
|
||||
import AztecoRedeem from './screen/receive/aztecoRedeem';
|
||||
|
||||
import SendDetails from './screen/send/details';
|
||||
import ScanQRCode from './screen/send/ScanQRCode';
|
||||
|
@ -205,6 +206,14 @@ const HandleOffchainAndOnChain = () => (
|
|||
</HandleOffchainAndOnChainStack.Navigator>
|
||||
);
|
||||
|
||||
const AztecoRedeemStack = createStackNavigator();
|
||||
const AztecoRedeemRoot = () => (
|
||||
<AztecoRedeemStack.Navigator>
|
||||
<AztecoRedeemStack.Screen name="AztecoRedeem" component={AztecoRedeem} options={AztecoRedeem.navigationOptions} />
|
||||
<AztecoRedeemStack.Screen name="SelectWallet" component={SelectWallet} options={{ headerLeft: null }} />
|
||||
</AztecoRedeemStack.Navigator>
|
||||
);
|
||||
|
||||
const RootStack = createStackNavigator();
|
||||
const Navigation = () => (
|
||||
<RootStack.Navigator mode="modal">
|
||||
|
@ -214,7 +223,8 @@ const Navigation = () => (
|
|||
<RootStack.Screen name="SendDetailsRoot" component={SendDetailsRoot} options={{ headerShown: false }} />
|
||||
<RootStack.Screen name="LNDCreateInvoiceRoot" component={LNDCreateInvoiceRoot} options={{ headerShown: false }} />
|
||||
<RootStack.Screen name="ScanLndInvoiceRoot" component={ScanLndInvoiceRoot} options={{ headerShown: false }} />
|
||||
<RootStack.Screen name="HandleOffchainAndOnChain" component={HandleOffchainAndOnChain} />
|
||||
<RootStack.Screen name="HandleOffchainAndOnChain" component={HandleOffchainAndOnChain} options={{ headerShown: false }} />
|
||||
<RootStack.Screen name="AztecoRedeemRoot" component={AztecoRedeemRoot} options={{ headerShown: false }} />
|
||||
{/* screens */}
|
||||
<RootStack.Screen name="WalletExport" component={WalletExport} options={WalletExport.navigationOptions} />
|
||||
<RootStack.Screen name="WalletXpub" component={WalletXpub} options={WalletXpub.navigationOptions} />
|
||||
|
|
41
class/azteco.js
Normal file
41
class/azteco.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import Frisbee from 'frisbee';
|
||||
import url from 'url';
|
||||
|
||||
export default class Azteco {
|
||||
/**
|
||||
* Redeems an Azteco bitcoin voucher.
|
||||
*
|
||||
* @param {string[]} voucher - 16-digit voucher code in groups of 4.
|
||||
* @param {string} address - Bitcoin address to send the redeemed bitcoin to.
|
||||
*
|
||||
* @returns {Promise<boolean>} Successfully redeemed or not. This method does not throw exceptions
|
||||
*/
|
||||
static async redeem(voucher, address) {
|
||||
const api = new Frisbee({
|
||||
baseURI: 'https://azte.co/',
|
||||
});
|
||||
const url = `/blue_despatch.php?CODE_1=${voucher[0]}&CODE_2=${voucher[1]}&CODE_3=${voucher[2]}&CODE_4=${voucher[3]}&ADDRESS=${address}`;
|
||||
|
||||
try {
|
||||
let response = await api.get(url);
|
||||
return response && response.originalResponse && +response.originalResponse.status === 200;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static isRedeemUrl(u) {
|
||||
return u.startsWith('https://azte.co');
|
||||
}
|
||||
|
||||
static getParamsFromUrl(u) {
|
||||
let urlObject = url.parse(u, true); // eslint-disable-line
|
||||
return {
|
||||
uri: u,
|
||||
c1: urlObject.query.c1,
|
||||
c2: urlObject.query.c2,
|
||||
c3: urlObject.query.c3,
|
||||
c4: urlObject.query.c4,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import BitcoinBIP70TransactionDecode from '../bip70/bip70';
|
|||
import RNFS from 'react-native-fs';
|
||||
import url from 'url';
|
||||
import { Chain } from '../models/bitcoinUnits';
|
||||
import Azteco from './azteco';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const bip21 = require('bip21');
|
||||
const BlueApp: AppStorage = require('../BlueApp');
|
||||
|
@ -27,7 +28,7 @@ class DeeplinkSchemaMatch {
|
|||
* navigation dictionary required by react-navigation
|
||||
*
|
||||
* @param event {{url: string}} URL deeplink as passed to app, e.g. `bitcoin:bc1qh6tf004ty7z7un2v5ntu4mkf630545gvhs45u7?amount=666&label=Yo`
|
||||
* @param completionHandler {function} Returns [string, params: object]
|
||||
* @param completionHandler {function} Callback that returns [string, params: object]
|
||||
*/
|
||||
static navigationRouteFor(event, completionHandler) {
|
||||
if (event.url === null) {
|
||||
|
@ -118,9 +119,17 @@ class DeeplinkSchemaMatch {
|
|||
safelloStateToken,
|
||||
},
|
||||
]);
|
||||
} else if (Azteco.isRedeemUrl(event.url)) {
|
||||
completionHandler([
|
||||
'AztecoRedeemRoot',
|
||||
{
|
||||
screen: 'AztecoRedeem',
|
||||
params: Azteco.getParamsFromUrl(event.url),
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
let urlObject = url.parse(event.url, true); // eslint-disable-line
|
||||
console.log('parsed', urlObject);
|
||||
console.log('parsed', event.url, 'into', urlObject);
|
||||
(async () => {
|
||||
if (urlObject.protocol === 'bluewallet:' || urlObject.protocol === 'lapp:' || urlObject.protocol === 'blue:') {
|
||||
switch (urlObject.host) {
|
||||
|
|
|
@ -20,7 +20,7 @@ export default class WalletGradient {
|
|||
static hdLegacyBreadWallet = ['#fe6381', '#f99c42'];
|
||||
static defaultGradients = ['#c65afb', '#9053fe'];
|
||||
static lightningCustodianWallet = ['#f1be07', '#f79056'];
|
||||
static createWallet = ['#eef0f4', '#eef0f4'];
|
||||
static createWallet = '#eef0f4';
|
||||
|
||||
static gradientsFor(type) {
|
||||
let gradient;
|
||||
|
@ -54,9 +54,6 @@ export default class WalletGradient {
|
|||
case SegwitBech32Wallet.type:
|
||||
gradient = WalletGradient.segwitBech32Wallet;
|
||||
break;
|
||||
case 'CreateWallet':
|
||||
gradient = WalletGradient.createWallet;
|
||||
break;
|
||||
default:
|
||||
gradient = WalletGradient.defaultGradients;
|
||||
break;
|
||||
|
@ -93,9 +90,6 @@ export default class WalletGradient {
|
|||
case LightningCustodianWallet.type:
|
||||
gradient = WalletGradient.lightningCustodianWallet;
|
||||
break;
|
||||
case 'CreateWallet':
|
||||
gradient = WalletGradient.createWallet;
|
||||
break;
|
||||
default:
|
||||
gradient = WalletGradient.defaultGradients;
|
||||
break;
|
||||
|
|
|
@ -196,13 +196,13 @@ PODS:
|
|||
- React
|
||||
- react-native-blur (0.8.0):
|
||||
- React
|
||||
- react-native-camera (3.23.1):
|
||||
- react-native-camera (3.26.0):
|
||||
- React
|
||||
- react-native-camera/RCT (= 3.23.1)
|
||||
- react-native-camera/RN (= 3.23.1)
|
||||
- react-native-camera/RCT (3.23.1):
|
||||
- react-native-camera/RCT (= 3.26.0)
|
||||
- react-native-camera/RN (= 3.26.0)
|
||||
- react-native-camera/RCT (3.26.0):
|
||||
- React
|
||||
- react-native-camera/RN (3.23.1):
|
||||
- react-native-camera/RN (3.26.0):
|
||||
- React
|
||||
- react-native-document-picker (3.2.0):
|
||||
- React
|
||||
|
@ -281,7 +281,7 @@ PODS:
|
|||
- React
|
||||
- RNSecureKeyStore (1.0.0):
|
||||
- React
|
||||
- RNSentry (1.3.5):
|
||||
- RNSentry (1.3.7):
|
||||
- React
|
||||
- Sentry (~> 4.4.0)
|
||||
- RNShare (2.0.0):
|
||||
|
@ -513,7 +513,7 @@ SPEC CHECKSUMS:
|
|||
react-native-biometrics: c892904948a32295b128f633bcc11eda020645c5
|
||||
react-native-blue-crypto: 23f1558ad3d38d7a2edb7e2f6ed1bc520ed93e56
|
||||
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
|
||||
react-native-camera: 6fe72fd0a85732e2449928f9c59a2e0bf661ad3b
|
||||
react-native-camera: 9e3d60336e221d62e5b72adf551ca31ff74a94b5
|
||||
react-native-document-picker: e3516aff0dcf65ee0785d9bcf190eb10e2261154
|
||||
react-native-image-picker: 3637d63fef7e32a230141ab4660d3ceb773c824f
|
||||
react-native-randombytes: 991545e6eaaf700b4ee384c291ef3d572e0b2ca8
|
||||
|
@ -545,7 +545,7 @@ SPEC CHECKSUMS:
|
|||
RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071
|
||||
RNScreens: 62211832af51e0aebcf6e8c36bcf7dd65592f244
|
||||
RNSecureKeyStore: f1ad870e53806453039f650720d2845c678d89c8
|
||||
RNSentry: 8a47c89b65502d8d5b464dfb3aa5a13038e5bb08
|
||||
RNSentry: 370623102247ebea20191b5fb549ecc7a275b324
|
||||
RNShare: 8b171d4b43c1d886917fdd303bf7a4b87167b05c
|
||||
RNSVG: 8ba35cbeb385a52fd960fd28db9d7d18b4c2974f
|
||||
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
||||
|
|
|
@ -67,9 +67,9 @@ module.exports = {
|
|||
export_backup: 'Exportieren / Backup',
|
||||
buy_bitcoin: 'Bitcoin kaufen',
|
||||
show_xpub: 'Wallet XPUB zeigen',
|
||||
connected_to: 'Connected to',
|
||||
advanced: 'Advanced',
|
||||
use_with_hardware_wallet: 'Use with hardware wallet',
|
||||
connected_to: 'Verbunden mit',
|
||||
advanced: 'Fortgeschritten',
|
||||
use_with_hardware_wallet: 'Hardware Wallet nutzen',
|
||||
},
|
||||
export: {
|
||||
title: 'Wallet exportieren',
|
||||
|
|
263
package-lock.json
generated
263
package-lock.json
generated
|
@ -1813,9 +1813,12 @@
|
|||
}
|
||||
},
|
||||
"@react-native-community/async-storage": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.8.1.tgz",
|
||||
"integrity": "sha512-MA1fTp4SB7OOtDmNAwds6jIpiwwty1NIoFboWjEWkoyWW35zIuxlhHxD4joSy21aWEzUVwvv6JJ2hSsP/HTb7A=="
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.10.0.tgz",
|
||||
"integrity": "sha512-kPJwhUpBKLXGrBnUjx0JVSJvSEl5nPO+puJ3Uy9pMvika9uWeniRGZPQjUWWQimU5M7xhQ41d5I1OP82Q3Xx9A==",
|
||||
"requires": {
|
||||
"deep-assign": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@react-native-community/blur": {
|
||||
"version": "3.6.0",
|
||||
|
@ -2032,27 +2035,26 @@
|
|||
"from": "git+https://github.com/BlueWallet/react-native-qrcode-local-image.git"
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.15.4.tgz",
|
||||
"integrity": "sha512-l/auT1HtZM3KxjCGQHYO/K51ygnlcuOrM+7Ga8gUUbU9ZXDYw6jRi0+Af9aqXKmdDw1naNxr7OCSy6NBrLWVZw==",
|
||||
"version": "5.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.15.5.tgz",
|
||||
"integrity": "sha512-rqDvjk/EvogfdbZ4TiEpxM/lwpPKmq23z9YKEO4q81+1SwJNua53H60dOk9HpRU8nOJ1g84TMKT2Ov8H7sqDWA==",
|
||||
"requires": {
|
||||
"@sentry/core": "5.15.4",
|
||||
"@sentry/types": "5.15.4",
|
||||
"@sentry/utils": "5.15.4",
|
||||
"@sentry/core": "5.15.5",
|
||||
"@sentry/types": "5.15.5",
|
||||
"@sentry/utils": "5.15.5",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/cli": {
|
||||
"version": "1.52.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.52.1.tgz",
|
||||
"integrity": "sha512-XocAy3opa7bxWEbYQ9R/whbIb4BAX2YHXvfMoCwZRzLRy9cf85FYGQCMi8JA7wQd5PBmcxUh31AxcX7jAfMPCQ==",
|
||||
"version": "1.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.53.0.tgz",
|
||||
"integrity": "sha512-FgVR+AqPd1elj/HGTCg4FcQDVmIGwKGtaHDzHi2ipph9EOVYm6Ce0xYcHxYgKZuVyQMyg+zD5ZK3yHrB1AYlnw==",
|
||||
"requires": {
|
||||
"fs-copy-file-sync": "^1.1.1",
|
||||
"https-proxy-agent": "^4.0.0",
|
||||
"mkdirp": "^0.5.4",
|
||||
"node-fetch": "^2.1.2",
|
||||
"progress": "2.0.0",
|
||||
"proxy-from-env": "^1.0.0"
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"mkdirp": "^0.5.5",
|
||||
"node-fetch": "^2.6.0",
|
||||
"progress": "^2.0.3",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
|
@ -2062,84 +2064,89 @@
|
|||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.15.4.tgz",
|
||||
"integrity": "sha512-9KP4NM4SqfV5NixpvAymC7Nvp36Zj4dU2fowmxiq7OIbzTxGXDhwuN/t0Uh8xiqlkpkQqSECZ1OjSFXrBldetQ==",
|
||||
"version": "5.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.15.5.tgz",
|
||||
"integrity": "sha512-enxBLv5eibBMqcWyr+vApqeix8uqkfn0iGsD3piKvoMXCgKsrfMwlb/qo9Ox0lKr71qIlZVt+9/A2vZohdgnlg==",
|
||||
"requires": {
|
||||
"@sentry/hub": "5.15.4",
|
||||
"@sentry/minimal": "5.15.4",
|
||||
"@sentry/types": "5.15.4",
|
||||
"@sentry/utils": "5.15.4",
|
||||
"@sentry/hub": "5.15.5",
|
||||
"@sentry/minimal": "5.15.5",
|
||||
"@sentry/types": "5.15.5",
|
||||
"@sentry/utils": "5.15.5",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.15.4.tgz",
|
||||
"integrity": "sha512-1XJ1SVqadkbUT4zLS0TVIVl99si7oHizLmghR8LMFl5wOkGEgehHSoOydQkIAX2C7sJmaF5TZ47ORBHgkqclUg==",
|
||||
"version": "5.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.15.5.tgz",
|
||||
"integrity": "sha512-zX9o49PcNIVMA4BZHe//GkbQ4Jx+nVofqU/Il32/IbwKhcpPlhGX3c1sOVQo4uag3cqd/JuQsk+DML9TKkN0Lw==",
|
||||
"requires": {
|
||||
"@sentry/types": "5.15.4",
|
||||
"@sentry/utils": "5.15.4",
|
||||
"@sentry/types": "5.15.5",
|
||||
"@sentry/utils": "5.15.5",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/integrations": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.15.4.tgz",
|
||||
"integrity": "sha512-GaEVQf4R+WBJvTOGptOHIFSylnH1JAvBQZ7c45jGIDBp+upqzeI67KD+HoM4sSNT2Y2i8DLTJCWibe34knz5Kw==",
|
||||
"version": "5.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.15.5.tgz",
|
||||
"integrity": "sha512-s9N9altnGkDH+vNNUZu1dKuMVLAgJNYtgs6DMJTrZRswFl8gzZytYTZCdpzjBgTsqkLaGbRDIjQeE/yP3gnrqw==",
|
||||
"requires": {
|
||||
"@sentry/types": "5.15.4",
|
||||
"@sentry/utils": "5.15.4",
|
||||
"@sentry/types": "5.15.5",
|
||||
"@sentry/utils": "5.15.5",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.15.4.tgz",
|
||||
"integrity": "sha512-GL4GZ3drS9ge+wmxkHBAMEwulaE7DMvAEfKQPDAjg2p3MfcCMhAYfuY4jJByAC9rg9OwBGGehz7UmhWMFjE0tw==",
|
||||
"version": "5.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.15.5.tgz",
|
||||
"integrity": "sha512-zQkkJ1l9AjmU/Us5IrOTzu7bic4sTPKCatptXvLSTfyKW7N6K9MPIIFeSpZf9o1yM2sRYdK7GV08wS2eCT3JYw==",
|
||||
"requires": {
|
||||
"@sentry/hub": "5.15.4",
|
||||
"@sentry/types": "5.15.4",
|
||||
"@sentry/hub": "5.15.5",
|
||||
"@sentry/types": "5.15.5",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/react-native": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-1.3.5.tgz",
|
||||
"integrity": "sha512-shgh3Nq9f43CVvrFgb8wBr5sdOWX0T2j0GQ2h1+JR4YvB7vGjIq1xCEZWql4GeAiImnzg15JNnsLAsgOWxF84A==",
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-1.3.7.tgz",
|
||||
"integrity": "sha512-Nv19bQOimEU4v8tvaiRD4M9mhbiU4HL8JJypA84HCYAG3CeBIQAwrA0lHIgk08ieBz7VKYzOJHBzOANDw3mAjg==",
|
||||
"requires": {
|
||||
"@sentry/browser": "^5.15.2",
|
||||
"@sentry/core": "^5.15.2",
|
||||
"@sentry/integrations": "^5.15.2",
|
||||
"@sentry/types": "^5.15.2",
|
||||
"@sentry/utils": "^5.15.2",
|
||||
"@sentry/browser": "^5.15.4",
|
||||
"@sentry/core": "^5.15.4",
|
||||
"@sentry/integrations": "^5.15.4",
|
||||
"@sentry/types": "^5.15.4",
|
||||
"@sentry/utils": "^5.15.4",
|
||||
"@sentry/wizard": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.15.4.tgz",
|
||||
"integrity": "sha512-quPHPpeAuwID48HLPmqBiyXE3xEiZLZ5D3CEbU3c3YuvvAg8qmfOOTI6z4Z3Eedi7flvYpnx3n7N3dXIEz30Eg=="
|
||||
"version": "5.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.15.5.tgz",
|
||||
"integrity": "sha512-F9A5W7ucgQLJUG4LXw1ZIy4iLevrYZzbeZ7GJ09aMlmXH9PqGThm1t5LSZlVpZvUfQ2rYA8NU6BdKJSt7B5LPw=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.15.4.tgz",
|
||||
"integrity": "sha512-lO8SLBjrUDGADl0LOkd55R5oL510d/1SaI08/IBHZCxCUwI4TiYo5EPECq8mrj3XGfgCyq9osw33bymRlIDuSQ==",
|
||||
"version": "5.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.15.5.tgz",
|
||||
"integrity": "sha512-Nl9gl/MGnzSkuKeo3QaefoD/OJrFLB8HmwQ7HUbTXb6E7yyEzNKAQMHXGkwNAjbdYyYbd42iABP6Y5F/h39NtA==",
|
||||
"requires": {
|
||||
"@sentry/types": "5.15.4",
|
||||
"@sentry/types": "5.15.5",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/wizard": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/wizard/-/wizard-1.1.2.tgz",
|
||||
"integrity": "sha512-z7Ck5uli91omT+xSGzOXA3XNj0IUFritzZ5Qjf/KcuSUZuyqLCH2olAR6pXl262tC6kBbWw/xb+AOgPsAQ7u/Q==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/wizard/-/wizard-1.1.4.tgz",
|
||||
"integrity": "sha512-xVpL0lnQK2bbEwUKKjs3dKhy27va8HW75Q8r1vaR63iBCpB5LpP4Q4NN5G/VEWdYnH8rcazsOA207716E1cm4g==",
|
||||
"requires": {
|
||||
"@sentry/cli": "^1.51.0",
|
||||
"@sentry/cli": "^1.52.4",
|
||||
"chalk": "^2.4.1",
|
||||
"glob": "^7.1.3",
|
||||
"inquirer": "^6.2.0",
|
||||
|
@ -2381,6 +2388,11 @@
|
|||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"abortcontroller-polyfill": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.4.0.tgz",
|
||||
"integrity": "sha512-3ZFfCRfDzx3GFjO6RAkYx81lPGpUS20ISxux9gLxuKnqafNcFQo59+IoZqpO2WvQlyc287B62HDnDdNYRmlvWA=="
|
||||
},
|
||||
"absolute-path": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz",
|
||||
|
@ -2447,9 +2459,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
|
||||
"integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g=="
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz",
|
||||
"integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==",
|
||||
"requires": {
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.0",
|
||||
|
@ -3853,6 +3868,11 @@
|
|||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||
},
|
||||
"boolean": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz",
|
||||
"integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA=="
|
||||
},
|
||||
"boolify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/boolify/-/boolify-1.0.1.tgz",
|
||||
|
@ -3983,17 +4003,26 @@
|
|||
}
|
||||
},
|
||||
"browserify-sign": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
|
||||
"integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz",
|
||||
"integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==",
|
||||
"requires": {
|
||||
"bn.js": "^4.1.1",
|
||||
"browserify-rsa": "^4.0.0",
|
||||
"create-hash": "^1.1.0",
|
||||
"create-hmac": "^1.1.2",
|
||||
"elliptic": "^6.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"parse-asn1": "^5.0.0"
|
||||
"bn.js": "^5.1.1",
|
||||
"browserify-rsa": "^4.0.1",
|
||||
"create-hash": "^1.2.0",
|
||||
"create-hmac": "^1.1.7",
|
||||
"elliptic": "^6.5.2",
|
||||
"inherits": "^2.0.4",
|
||||
"parse-asn1": "^5.1.5",
|
||||
"readable-stream": "^3.6.0",
|
||||
"safe-buffer": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz",
|
||||
"integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"browserify-zlib": {
|
||||
|
@ -4938,6 +4967,14 @@
|
|||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz",
|
||||
"integrity": "sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s="
|
||||
},
|
||||
"deep-assign": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-3.0.0.tgz",
|
||||
"integrity": "sha512-YX2i9XjJ7h5q/aQ/IM9PEwEnDqETAIYbggmdDB3HLTlSgo1CxPsj6pvhPG68rq6SVE0+p+6Ywsm5fTYNrYtBWw==",
|
||||
"requires": {
|
||||
"is-obj": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"deep-equal": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
|
||||
|
@ -5070,9 +5107,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"detox": {
|
||||
"version": "16.4.0",
|
||||
"resolved": "https://registry.npmjs.org/detox/-/detox-16.4.0.tgz",
|
||||
"integrity": "sha512-2dB6bJ9GCM7BuZCWubSRQLX1QLaKvPue9zu4+jcDMhhbQL08KKIClb2yelMalSyjtM04hX7OUw+SBArIwU13Dg==",
|
||||
"version": "16.6.0",
|
||||
"resolved": "https://registry.npmjs.org/detox/-/detox-16.6.0.tgz",
|
||||
"integrity": "sha512-2FziZMJ2+fEEwNCR1kfZ/e/CqTFIJXC1jRHdyK1t3oePfT1Qq+V22ejdfxs061b1o9AsoJrjPqi+It8AOaQCsw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/core": "^7.4.5",
|
||||
|
@ -6757,22 +6794,22 @@
|
|||
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||
},
|
||||
"frisbee": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/frisbee/-/frisbee-2.0.9.tgz",
|
||||
"integrity": "sha512-k2YrtBki5iw0p2Wsee5KW0cQBpzvDAOcAXMcunNCwM31XCj4RFpa1WGA4541JY9wFz8QhTHBQXb2rE3ERvbr9w==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/frisbee/-/frisbee-3.1.2.tgz",
|
||||
"integrity": "sha512-qkhtfxUsTFS2BfWJcSKXWAMYPq9RhJkcrikOGPxvzhklI+RAM8tWd1V7n3t6V1uwPNjfPegNG5q1r5Yp3zXOFw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.7.4",
|
||||
"abortcontroller-polyfill": "^1.4.0",
|
||||
"boolean": "^3.0.0",
|
||||
"caseless": "^0.12.0",
|
||||
"common-tags": "^1.8.0",
|
||||
"cross-fetch": "^3.0.2",
|
||||
"qs": "^6.7.0",
|
||||
"url-join": "^4.0.0"
|
||||
"cross-fetch": "^3.0.4",
|
||||
"debug": "^4.1.1",
|
||||
"qs": "6.9.1",
|
||||
"url-join": "^4.0.1",
|
||||
"url-parse": "^1.4.7"
|
||||
}
|
||||
},
|
||||
"fs-copy-file-sync": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz",
|
||||
"integrity": "sha512-2QY5eeqVv4m2PfyMiEuy9adxNP+ajf+8AR05cEi+OAzPcOj90hvFImeZhTmKLBgSd9EvG33jsD7ZRxsx9dThkQ=="
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
|
||||
|
@ -7670,11 +7707,11 @@
|
|||
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
|
||||
"integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
|
||||
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
|
||||
"requires": {
|
||||
"agent-base": "5",
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
|
@ -8001,6 +8038,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"is-obj": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
|
||||
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
|
||||
},
|
||||
"is-object": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-object/-/is-object-0.1.2.tgz",
|
||||
|
@ -10288,9 +10330,9 @@
|
|||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.24.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
|
||||
"version": "2.26.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz",
|
||||
"integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
|
@ -10436,11 +10478,12 @@
|
|||
"integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
|
||||
},
|
||||
"node-libs-react-native": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-react-native/-/node-libs-react-native-1.0.3.tgz",
|
||||
"integrity": "sha512-2X/M/DMB4hij2L0tsnJOiDhYR2N0YtetIhb/eN5+5vksLxjXwaFgLbSXWT3XExnGJpISDn8dYuYz6yvdndjjkg==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-react-native/-/node-libs-react-native-1.2.0.tgz",
|
||||
"integrity": "sha512-D+g8Mj9OfsOYYFWZoSz4bmr/8g/QWOwUgDmi3Ux0EPU9Q41OvGsdzAzr0IGJmtuSAfyOTfnKx1XRQR9id8/EEw==",
|
||||
"requires": {
|
||||
"assert": "^1.4.1",
|
||||
"base-64": "^0.1.0",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"buffer": "^5.0.6",
|
||||
"console-browserify": "^1.1.0",
|
||||
|
@ -11762,7 +11805,8 @@
|
|||
"progress": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
|
||||
"integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8="
|
||||
"integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
|
||||
"dev": true
|
||||
},
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
|
@ -11977,6 +12021,11 @@
|
|||
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
|
||||
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
|
||||
},
|
||||
"querystringify": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
|
||||
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
|
||||
},
|
||||
"quick-lru": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
|
||||
|
@ -12386,9 +12435,9 @@
|
|||
"from": "git+https://github.com/Overtorment/react-native-blue-crypto.git"
|
||||
},
|
||||
"react-native-camera": {
|
||||
"version": "3.23.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.23.1.tgz",
|
||||
"integrity": "sha512-ghQT2IhiZiNMDgixD/MrfwgFx9arwOb2z79xDJ8dsz8DFcpBMbXjXZETaAK0WaZ/MWOaY84k0eGlx1hoVT77wQ==",
|
||||
"version": "3.26.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.26.0.tgz",
|
||||
"integrity": "sha512-W/h89LN+jujlzc89nWpvukbfnbFO+Fskf6PR23pP6zminpJDIArHabWLd1mQoJ3p6r+gUJ8I4bgsxUmSMgLAgA==",
|
||||
"requires": {
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
|
@ -13183,6 +13232,11 @@
|
|||
"integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
|
||||
"dev": true
|
||||
},
|
||||
"requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
|
||||
|
@ -14652,6 +14706,15 @@
|
|||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
||||
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
|
||||
"integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"use": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||
|
|
12
package.json
12
package.json
|
@ -10,7 +10,7 @@
|
|||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.0.1",
|
||||
"babel-preset-flow": "^6.23.0",
|
||||
"detox": "^16.4.0",
|
||||
"detox": "16.6.0",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-plugin-babel": "^5.3.0",
|
||||
"eslint-plugin-import": "^2.18.0",
|
||||
|
@ -63,14 +63,14 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "7.9.6",
|
||||
"@react-native-community/async-storage": "1.8.1",
|
||||
"@react-native-community/async-storage": "1.10.0",
|
||||
"@react-native-community/blur": "3.6.0",
|
||||
"@react-native-community/masked-view": "0.1.10",
|
||||
"@react-native-community/slider": "2.0.8",
|
||||
"@react-navigation/native": "5.4.3",
|
||||
"@react-navigation/stack": "5.4.0",
|
||||
"@remobile/react-native-qrcode-local-image": "git+https://github.com/BlueWallet/react-native-qrcode-local-image.git",
|
||||
"@sentry/react-native": "1.3.5",
|
||||
"@sentry/react-native": "1.3.7",
|
||||
"amplitude-js": "5.9.0",
|
||||
"bech32": "1.1.3",
|
||||
"bignumber.js": "9.0.0",
|
||||
|
@ -93,10 +93,10 @@
|
|||
"eslint-plugin-prettier": "3.1.2",
|
||||
"eslint-plugin-standard": "4.0.0",
|
||||
"events": "1.1.1",
|
||||
"frisbee": "2.0.9",
|
||||
"frisbee": "3.1.2",
|
||||
"intl": "1.2.5",
|
||||
"lottie-react-native": "3.1.1",
|
||||
"node-libs-react-native": "1.0.3",
|
||||
"node-libs-react-native": "1.2.0",
|
||||
"path-browserify": "1.0.0",
|
||||
"pbkdf2": "3.0.17",
|
||||
"prettier": "1.19.1",
|
||||
|
@ -107,7 +107,7 @@
|
|||
"react-native": "0.61.5",
|
||||
"react-native-biometrics": "git+https://github.com/BlueWallet/react-native-biometrics.git#2.0.0",
|
||||
"react-native-blue-crypto": "git+https://github.com/Overtorment/react-native-blue-crypto.git",
|
||||
"react-native-camera": "3.23.1",
|
||||
"react-native-camera": "3.26.0",
|
||||
"react-native-default-preference": "1.4.1",
|
||||
"react-native-device-info": "4.0.1",
|
||||
"react-native-document-picker": "git+https://github.com/BlueWallet/react-native-document-picker.git#9ce83792db340d01b1361d24b19613658abef4aa",
|
||||
|
|
148
screen/receive/aztecoRedeem.js
Normal file
148
screen/receive/aztecoRedeem.js
Normal file
|
@ -0,0 +1,148 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { Keyboard, Text, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { BlueButton, BlueCreateTxNavigationStyle, BlueLoading, BlueSpacing, BlueText } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { AppStorage, PlaceholderWallet } from '../../class';
|
||||
import Azteco from '../../class/azteco';
|
||||
|
||||
const EV = require('../../events');
|
||||
let BlueApp: AppStorage = require('../../BlueApp');
|
||||
|
||||
export default class AztecoRedeem extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueCreateTxNavigationStyle(navigation),
|
||||
title: 'Redeem Azte.co voucher',
|
||||
});
|
||||
|
||||
state = { isLoading: true };
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
/** @type {AbstractWallet} */
|
||||
let toWallet = null;
|
||||
|
||||
const wallets = BlueApp.getWallets().filter(wallet => wallet.type !== PlaceholderWallet.type);
|
||||
|
||||
if (wallets.length === 0) {
|
||||
alert('Before redeeming you must first add a Bitcoin wallet.');
|
||||
return props.navigation.goBack(null);
|
||||
} else {
|
||||
if (wallets.length > 0) {
|
||||
toWallet = wallets[0];
|
||||
}
|
||||
this.state = {
|
||||
c1: props.route.params.c1,
|
||||
c2: props.route.params.c2,
|
||||
c3: props.route.params.c3,
|
||||
c4: props.route.params.c4,
|
||||
isLoading: false,
|
||||
toWallet,
|
||||
renderWalletSelectionButtonHidden: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('AztecoRedeem - componentDidMount');
|
||||
}
|
||||
|
||||
onWalletSelect = toWallet => {
|
||||
this.setState({ toWallet }, () => {
|
||||
this.props.navigation.pop();
|
||||
});
|
||||
};
|
||||
|
||||
redeem = async () => {
|
||||
this.setState({ isLoading: true });
|
||||
const address = await this.state.toWallet.getAddressAsync();
|
||||
const result = await Azteco.redeem([this.state.c1, this.state.c2, this.state.c3, this.state.c4], address);
|
||||
if (!result) {
|
||||
alert('Something went wrong. Is this voucher still valid?');
|
||||
this.setState({ isLoading: false });
|
||||
} else {
|
||||
this.props.navigation.pop();
|
||||
// remote because we want to refetch from server tx list and balance
|
||||
setTimeout(() => EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED), 4000);
|
||||
alert('Success');
|
||||
}
|
||||
};
|
||||
|
||||
renderWalletSelectionButton = () => {
|
||||
if (this.state.renderWalletSelectionButtonHidden) return;
|
||||
return (
|
||||
<View style={{ marginBottom: 24, alignItems: 'center' }}>
|
||||
{!this.state.isLoading && (
|
||||
<TouchableOpacity
|
||||
style={{ flexDirection: 'row', alignItems: 'center' }}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('SelectWallet', {
|
||||
onWalletSelect: this.onWalletSelect,
|
||||
availableWallets: BlueApp.getWallets(),
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={{ color: '#9aa0aa', fontSize: 14, marginRight: 8 }}>Redeem to wallet</Text>
|
||||
<Icon name="angle-right" size={18} type="font-awesome" color="#9aa0aa" />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginVertical: 4 }}>
|
||||
<TouchableOpacity
|
||||
style={{ flexDirection: 'row', alignItems: 'center' }}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('SelectWallet', {
|
||||
onWalletSelect: this.onWalletSelect,
|
||||
availableWallets: BlueApp.getWallets(),
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={{ color: '#0c2550', fontSize: 14 }}>{this.state.toWallet.getLabel()}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading || typeof this.state.toWallet === 'undefined') {
|
||||
return (
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueLoading />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
||||
<View>
|
||||
<View style={{ alignItems: 'center', alignContent: 'flex-end', marginTop: 66 }}>
|
||||
<Text>Your voucher code is</Text>
|
||||
<BlueText style={{ color: '#0c2550', fontSize: 20, marginTop: 20, marginBottom: 90 }}>
|
||||
{this.state.c1}-{this.state.c2}-{this.state.c3}-{this.state.c4}
|
||||
</BlueText>
|
||||
{this.renderWalletSelectionButton()}
|
||||
<BlueButton onPress={this.redeem} title={'Redeem'} />
|
||||
<BlueSpacing />
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AztecoRedeem.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
pop: PropTypes.func,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
}),
|
||||
route: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
c1: PropTypes.string,
|
||||
c2: PropTypes.string,
|
||||
c3: PropTypes.string,
|
||||
c4: PropTypes.string,
|
||||
}),
|
||||
}),
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { View, InteractionManager, Platform, TextInput, KeyboardAvoidingView, Keyboard, StyleSheet, ScrollView } from 'react-native';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { useNavigation, useRoute, useIsFocused } from '@react-navigation/native';
|
||||
import {
|
||||
BlueLoading,
|
||||
SafeBlueArea,
|
||||
|
@ -38,6 +38,7 @@ const ReceiveDetails = () => {
|
|||
const [isCustom, setIsCustom] = useState(false);
|
||||
const [isCustomModalVisible, setIsCustomModalVisible] = useState(false);
|
||||
const { navigate, goBack } = useNavigation();
|
||||
const isFocused = useIsFocused();
|
||||
|
||||
const renderReceiveDetails = useCallback(async () => {
|
||||
console.log('receive/details - componentDidMount');
|
||||
|
@ -210,7 +211,7 @@ const ReceiveDetails = () => {
|
|||
</BlueText>
|
||||
</>
|
||||
)}
|
||||
{bip21encoded === undefined ? (
|
||||
{bip21encoded === undefined && isFocused ? (
|
||||
<View style={{ alignItems: 'center', width: 300, height: 300 }}>
|
||||
<BlueLoading />
|
||||
</View>
|
||||
|
|
|
@ -4,20 +4,20 @@ import { Image, View, TouchableOpacity, Platform } from 'react-native';
|
|||
import { RNCamera } from 'react-native-camera';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import ImagePicker from 'react-native-image-picker';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { useNavigation, useRoute, useIsFocused } from '@react-navigation/native';
|
||||
import DocumentPicker from 'react-native-document-picker';
|
||||
import RNFS from 'react-native-fs';
|
||||
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
|
||||
const createHash = require('create-hash');
|
||||
|
||||
const ScanQRCode = ({ showCloseButton = true, showFileImportButton: showFileImportButtonProps }) => {
|
||||
const ScanQRCode = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { navigate } = useNavigation();
|
||||
const route = useRoute();
|
||||
const showFileImportButton = showFileImportButtonProps || route.params.showFileImportButton || false;
|
||||
const showFileImportButton = route.params.showFileImportButton || false;
|
||||
const { launchedBy, onBarScanned } = route.params;
|
||||
const scannedCache = {};
|
||||
const isFocused = useIsFocused();
|
||||
|
||||
const HashIt = function(s) {
|
||||
return createHash('sha256')
|
||||
|
@ -37,7 +37,7 @@ const ScanQRCode = ({ showCloseButton = true, showFileImportButton: showFileImpo
|
|||
if (!isLoading) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
if (showCloseButton && launchedBy) {
|
||||
if (launchedBy) {
|
||||
navigate(launchedBy);
|
||||
}
|
||||
if (ret.additionalProperties) {
|
||||
|
@ -76,9 +76,39 @@ const ScanQRCode = ({ showCloseButton = true, showFileImportButton: showFileImpo
|
|||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const showImagePicker = () => {
|
||||
if (!isLoading) {
|
||||
setIsLoading(true);
|
||||
ImagePicker.launchImageLibrary(
|
||||
{
|
||||
title: null,
|
||||
mediaType: 'photo',
|
||||
takePhotoButtonTitle: null,
|
||||
},
|
||||
response => {
|
||||
if (response.uri) {
|
||||
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
|
||||
LocalQRCode.decode(uri, (error, result) => {
|
||||
if (!error) {
|
||||
onBarCodeRead({ data: result });
|
||||
} else {
|
||||
alert('The selected image does not contain a QR Code.');
|
||||
}
|
||||
});
|
||||
}
|
||||
setIsLoading(false);
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const dismiss = () => {
|
||||
navigate(launchedBy);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: '#000000' }}>
|
||||
{!isLoading && (
|
||||
{!isLoading && isFocused && (
|
||||
<RNCamera
|
||||
captureAudio={false}
|
||||
androidCameraPermissionOptions={{
|
||||
|
@ -87,28 +117,26 @@ const ScanQRCode = ({ showCloseButton = true, showFileImportButton: showFileImpo
|
|||
buttonPositive: 'OK',
|
||||
buttonNegative: 'Cancel',
|
||||
}}
|
||||
style={{ flex: 1, justifyContent: 'space-between', backgroundColor: '#000000' }}
|
||||
style={{ flex: 1 }}
|
||||
onBarCodeRead={onBarCodeRead}
|
||||
barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
|
||||
/>
|
||||
)}
|
||||
{showCloseButton && (
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
backgroundColor: 'rgba(0,0,0,0.4)',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 20,
|
||||
position: 'absolute',
|
||||
right: 16,
|
||||
top: 44,
|
||||
}}
|
||||
onPress={() => navigate(launchedBy)}
|
||||
>
|
||||
<Image style={{ alignSelf: 'center' }} source={require('../../img/close-white.png')} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
backgroundColor: 'rgba(0,0,0,0.4)',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 20,
|
||||
position: 'absolute',
|
||||
right: 16,
|
||||
top: 44,
|
||||
}}
|
||||
onPress={dismiss}
|
||||
>
|
||||
<Image style={{ alignSelf: 'center' }} source={require('../../img/close-white.png')} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
width: 40,
|
||||
|
@ -120,31 +148,7 @@ const ScanQRCode = ({ showCloseButton = true, showFileImportButton: showFileImpo
|
|||
left: 24,
|
||||
bottom: 48,
|
||||
}}
|
||||
onPress={() => {
|
||||
if (!isLoading) {
|
||||
setIsLoading(true);
|
||||
ImagePicker.launchImageLibrary(
|
||||
{
|
||||
title: null,
|
||||
mediaType: 'photo',
|
||||
takePhotoButtonTitle: null,
|
||||
},
|
||||
response => {
|
||||
if (response.uri) {
|
||||
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
|
||||
LocalQRCode.decode(uri, (error, result) => {
|
||||
if (!error) {
|
||||
onBarCodeRead({ data: result });
|
||||
} else {
|
||||
alert('The selected image does not contain a QR Code.');
|
||||
}
|
||||
});
|
||||
}
|
||||
setIsLoading(false);
|
||||
},
|
||||
);
|
||||
}
|
||||
}}
|
||||
onPress={showImagePicker}
|
||||
>
|
||||
<Icon name="image" type="font-awesome" color="#ffffff" />
|
||||
</TouchableOpacity>
|
||||
|
@ -172,8 +176,5 @@ const ScanQRCode = ({ showCloseButton = true, showFileImportButton: showFileImpo
|
|||
ScanQRCode.navigationOptions = {
|
||||
headerShown: false,
|
||||
};
|
||||
ScanQRCode.propTypes = {
|
||||
showFileImportButton: PropTypes.bool,
|
||||
showCloseButton: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default ScanQRCode;
|
||||
|
|
|
@ -28,17 +28,24 @@ const loc = require('../../loc');
|
|||
const currency = require('../../currency');
|
||||
|
||||
export default class SendCreate extends Component {
|
||||
static navigationOptions = ({ navigation, route }) => ({
|
||||
...BlueNavigationStyle,
|
||||
title: loc.send.create.details,
|
||||
headerRight: route.params.exportTXN
|
||||
? () => (
|
||||
static navigationOptions = ({ navigation, route }) => {
|
||||
let headerRight;
|
||||
if (route.params.exportTXN) {
|
||||
headerRight = () => (
|
||||
<TouchableOpacity style={{ marginRight: 16 }} onPress={route.params.exportTXN}>
|
||||
<Icon size={22} name="share-alternative" type="entypo" color={BlueApp.settings.foregroundColor} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
: null,
|
||||
});
|
||||
<Icon size={22} name="share-alternative" type="entypo" color={BlueApp.settings.foregroundColor} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
} else {
|
||||
headerRight = null;
|
||||
}
|
||||
|
||||
return {
|
||||
...BlueNavigationStyle,
|
||||
title: loc.send.create.details,
|
||||
headerRight,
|
||||
};
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
|
@ -17,9 +17,14 @@ const NetworkSettings = () => {
|
|||
) : (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<ScrollView>
|
||||
<BlueListItem title={'Electrum server'} component={TouchableOpacity} onPress={() => navigate('ElectrumSettings')} />
|
||||
<BlueListItem title={loc.settings.lightning_settings} component={TouchableOpacity} onPress={() => navigate('LightningSettings')} />
|
||||
<BlueListItem title="Broadcast transaction" component={TouchableOpacity} onPress={() => navigate('Broadcast')} />
|
||||
<BlueListItem title={'Electrum server'} component={TouchableOpacity} onPress={() => navigate('ElectrumSettings')} chevron />
|
||||
<BlueListItem
|
||||
title={loc.settings.lightning_settings}
|
||||
component={TouchableOpacity}
|
||||
onPress={() => navigate('LightningSettings')}
|
||||
chevron
|
||||
/>
|
||||
<BlueListItem title="Broadcast transaction" component={TouchableOpacity} onPress={() => navigate('Broadcast')} chevron />
|
||||
</ScrollView>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
|
|
|
@ -85,7 +85,7 @@ const About = () => {
|
|||
<Text style={{ maxWidth: 260, marginBottom: 40, color: '#0C2550', fontSize: 15, textAlign: 'center', fontWeight: '500' }}>
|
||||
Always backup your keys!
|
||||
</Text>
|
||||
<BlueButton onPress={handleOnRatePress} title="help with a review ⭐🙏" />
|
||||
<BlueButton onPress={handleOnRatePress} title="Leave us a review ⭐🙏" />
|
||||
</View>
|
||||
</BlueCard>
|
||||
<BlueListItem
|
||||
|
|
|
@ -42,7 +42,7 @@ const Currency = () => {
|
|||
disabled={isSavingNewPreferredCurrency}
|
||||
title={`${item.endPointKey} (${item.symbol})`}
|
||||
{...(selectedCurrency.endPointKey === item.endPointKey
|
||||
? { rightIcon: <Icon name="check" type="font-awesome" color="#0c2550" /> }
|
||||
? { rightIcon: <Icon name="check" type="octaicon" color="#0070FF" /> }
|
||||
: { hideChevron: true })}
|
||||
Component={TouchableOpacity}
|
||||
onPress={async () => {
|
||||
|
|
|
@ -65,7 +65,7 @@ export default class Language extends Component {
|
|||
title={item.label}
|
||||
{...(this.state.language === item.value
|
||||
? {
|
||||
rightIcon: <Icon name="check" type="font-awesome" color="#0c2550" />,
|
||||
rightIcon: <Icon name="check" type="octaicon" color="#0070FF" />,
|
||||
}
|
||||
: { hideChevron: true })}
|
||||
/>
|
||||
|
|
|
@ -179,35 +179,41 @@ export default class WalletsAdd extends Component {
|
|||
<BlueSpacing20 />
|
||||
<Text style={{ color: '#0c2550', fontWeight: '500' }}>{loc.settings.advanced_options}</Text>
|
||||
<BlueListItem
|
||||
containerStyle={{ paddingHorizontal: 0 }}
|
||||
bottomDivider={false}
|
||||
onPress={() => {
|
||||
this.onSelect(0, HDSegwitBech32Wallet.type);
|
||||
}}
|
||||
title={HDSegwitBech32Wallet.typeReadable}
|
||||
{...(this.state.selectedIndex === 0
|
||||
? {
|
||||
rightIcon: <Icon name="check" type="font-awesome" color="#0c2550" />,
|
||||
rightIcon: <Icon name="check" type="octaicon" color="#0070FF" />,
|
||||
}
|
||||
: { hideChevron: true })}
|
||||
/>
|
||||
<BlueListItem
|
||||
containerStyle={{ paddingHorizontal: 0 }}
|
||||
bottomDivider={false}
|
||||
onPress={() => {
|
||||
this.onSelect(1, SegwitP2SHWallet.type);
|
||||
}}
|
||||
title={SegwitP2SHWallet.typeReadable}
|
||||
{...(this.state.selectedIndex === 1
|
||||
? {
|
||||
rightIcon: <Icon name="check" type="font-awesome" color="#0c2550" />,
|
||||
rightIcon: <Icon name="check" type="octaicon" color="#0070FF" />,
|
||||
}
|
||||
: { hideChevron: true })}
|
||||
/>
|
||||
<BlueListItem
|
||||
containerStyle={{ paddingHorizontal: 0 }}
|
||||
bottomDivider={false}
|
||||
onPress={() => {
|
||||
this.onSelect(2, HDSegwitP2SHWallet.typeReadable.type);
|
||||
}}
|
||||
title={HDSegwitP2SHWallet.typeReadable}
|
||||
{...(this.state.selectedIndex === 2
|
||||
? {
|
||||
rightIcon: <Icon name="check" type="font-awesome" color="#0c2550" />,
|
||||
rightIcon: <Icon name="check" type="octaicon" color="#0070FF" />,
|
||||
}
|
||||
: { hideChevron: true })}
|
||||
/>
|
||||
|
|
|
@ -1,18 +1,33 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { View, TouchableOpacity, Text, StyleSheet, InteractionManager, RefreshControl, SectionList, Alert, Platform } from 'react-native';
|
||||
import {
|
||||
StatusBar,
|
||||
View,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
StyleSheet,
|
||||
InteractionManager,
|
||||
Clipboard,
|
||||
RefreshControl,
|
||||
SectionList,
|
||||
Alert,
|
||||
Platform,
|
||||
} from 'react-native';
|
||||
import { BlueScanButton, WalletsCarousel, BlueHeaderDefaultMain, BlueTransactionListItem } from '../../BlueComponents';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
import PropTypes from 'prop-types';
|
||||
import { PlaceholderWallet } from '../../class';
|
||||
import { AppStorage, PlaceholderWallet } from '../../class';
|
||||
import WalletImport from '../../class/walletImport';
|
||||
let EV = require('../../events');
|
||||
let A = require('../../analytics');
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
let loc = require('../../loc');
|
||||
let BlueElectrum = require('../../BlueElectrum');
|
||||
import ActionSheet from '../ActionSheet';
|
||||
import ImagePicker from 'react-native-image-picker';
|
||||
const EV = require('../../events');
|
||||
const A = require('../../analytics');
|
||||
let BlueApp: AppStorage = require('../../BlueApp');
|
||||
const loc = require('../../loc');
|
||||
const BlueElectrum = require('../../BlueElectrum');
|
||||
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
|
||||
|
||||
const WalletsListSections = { CAROUSEL: 'CAROUSEL', LOCALTRADER: 'LOCALTRADER', TRANSACTIONS: 'TRANSACTIONS' };
|
||||
|
||||
|
@ -25,7 +40,6 @@ export default class WalletsList extends Component {
|
|||
isLoading: true,
|
||||
isFlatListRefreshControlHidden: true,
|
||||
wallets: BlueApp.getWallets().concat(false),
|
||||
lastSnappedTo: 0,
|
||||
timeElpased: 0,
|
||||
dataSource: [],
|
||||
};
|
||||
|
@ -37,8 +51,11 @@ export default class WalletsList extends Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
console.log('wallets/list componentDidMount');
|
||||
// the idea is that upon wallet launch we will refresh
|
||||
// all balances and all transactions here:
|
||||
this.redrawScreen();
|
||||
|
||||
InteractionManager.runAfterInteractions(async () => {
|
||||
try {
|
||||
await BlueElectrum.waitTillConnected();
|
||||
|
@ -54,12 +71,13 @@ export default class WalletsList extends Component {
|
|||
console.log(error);
|
||||
}
|
||||
});
|
||||
|
||||
this.interval = setInterval(() => {
|
||||
this.setState(prev => ({ timeElapsed: prev.timeElapsed + 1 }));
|
||||
}, 60000);
|
||||
this.redrawScreen();
|
||||
|
||||
this._unsubscribe = this.props.navigation.addListener('focus', this.redrawScreen);
|
||||
this._unsubscribe = this.props.navigation.addListener('focus', this.onNavigationEventFocus);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -71,12 +89,7 @@ export default class WalletsList extends Component {
|
|||
* Forcefully fetches TXs and balance for lastSnappedTo (i.e. current) wallet.
|
||||
* Triggered manually by user on pull-to-refresh.
|
||||
*/
|
||||
refreshTransactions() {
|
||||
if (!(this.lastSnappedTo < BlueApp.getWallets().length) && this.lastSnappedTo !== undefined) {
|
||||
// last card, nop
|
||||
console.log('last card, nop');
|
||||
return;
|
||||
}
|
||||
refreshTransactions = () => {
|
||||
this.setState(
|
||||
{
|
||||
isFlatListRefreshControlHidden: false,
|
||||
|
@ -88,11 +101,11 @@ export default class WalletsList extends Component {
|
|||
await BlueElectrum.ping();
|
||||
await BlueElectrum.waitTillConnected();
|
||||
let balanceStart = +new Date();
|
||||
await BlueApp.fetchWalletBalances(this.lastSnappedTo || 0);
|
||||
await BlueApp.fetchWalletBalances(this.walletsCarousel.current.currentIndex || 0);
|
||||
let balanceEnd = +new Date();
|
||||
console.log('fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec');
|
||||
let start = +new Date();
|
||||
await BlueApp.fetchWalletTransactions(this.lastSnappedTo || 0);
|
||||
await BlueApp.fetchWalletTransactions(this.walletsCarousel.current.currentIndex || 0);
|
||||
let end = +new Date();
|
||||
console.log('fetch tx took', (end - start) / 1000, 'sec');
|
||||
} catch (err) {
|
||||
|
@ -105,10 +118,16 @@ export default class WalletsList extends Component {
|
|||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
redrawScreen = (scrollToEnd = false) => {
|
||||
console.log('wallets/list redrawScreen()');
|
||||
|
||||
// here, when we receive REMOTE_TRANSACTIONS_COUNT_CHANGED we fetch TXs and balance for current wallet.
|
||||
// placing event subscription here so it gets exclusively re-subscribed more often. otherwise we would
|
||||
// have to unsubscribe on unmount and resubscribe again on mount.
|
||||
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED, this.refreshTransactions.bind(this), true);
|
||||
|
||||
if (BlueApp.getBalance() !== 0) {
|
||||
A(A.ENUM.GOT_NONZERO_BALANCE);
|
||||
} else {
|
||||
|
@ -187,9 +206,6 @@ export default class WalletsList extends Component {
|
|||
|
||||
onSnapToItem = index => {
|
||||
console.log('onSnapToItem', index);
|
||||
this.lastSnappedTo = index;
|
||||
this.setState({ lastSnappedTo: index });
|
||||
|
||||
if (index < BlueApp.getWallets().length) {
|
||||
// not the last
|
||||
}
|
||||
|
@ -296,7 +312,7 @@ export default class WalletsList extends Component {
|
|||
<View style={styles.headerStyle}>
|
||||
<TouchableOpacity
|
||||
testID="SettingsButton"
|
||||
style={{ marginHorizontal: 16 }}
|
||||
style={{ height: 48, paddingRight: 16, paddingLeft: 32, paddingVertical: 10 }}
|
||||
onPress={() => this.props.navigation.navigate('Settings')}
|
||||
>
|
||||
<Icon size={22} name="kebab-horizontal" type="octicon" color={BlueApp.settings.foregroundColor} />
|
||||
|
@ -434,7 +450,7 @@ export default class WalletsList extends Component {
|
|||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<BlueScanButton onPress={this.onScanButtonPressed} />
|
||||
<BlueScanButton onPress={this.onScanButtonPressed} onLongPress={this.sendButtonLongPress} />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
|
@ -461,15 +477,99 @@ export default class WalletsList extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
onNavigationEventFocus = () => {
|
||||
StatusBar.setBarStyle('dark-content');
|
||||
this.redrawScreen();
|
||||
};
|
||||
|
||||
choosePhoto = () => {
|
||||
ImagePicker.launchImageLibrary(
|
||||
{
|
||||
title: null,
|
||||
mediaType: 'photo',
|
||||
takePhotoButtonTitle: null,
|
||||
},
|
||||
response => {
|
||||
if (response.uri) {
|
||||
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
|
||||
LocalQRCode.decode(uri, (error, result) => {
|
||||
if (!error) {
|
||||
this.onBarScanned(result);
|
||||
} else {
|
||||
alert('The selected image does not contain a QR Code.');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
copyFromClipbard = async () => {
|
||||
this.onBarScanned(await Clipboard.getString());
|
||||
};
|
||||
|
||||
sendButtonLongPress = async () => {
|
||||
const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0;
|
||||
if (Platform.OS === 'ios') {
|
||||
let options = [loc.send.details.cancel, 'Choose Photo', 'Scan QR Code'];
|
||||
if (!isClipboardEmpty) {
|
||||
options.push('Copy from Clipboard');
|
||||
}
|
||||
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0 }, buttonIndex => {
|
||||
if (buttonIndex === 1) {
|
||||
this.choosePhoto();
|
||||
} else if (buttonIndex === 2) {
|
||||
this.props.navigation.navigate('ScanQRCode', {
|
||||
launchedBy: this.props.route.name,
|
||||
onBarScanned: this.onBarCodeRead,
|
||||
showFileImportButton: false,
|
||||
});
|
||||
} else if (buttonIndex === 3) {
|
||||
this.copyFromClipbard();
|
||||
}
|
||||
});
|
||||
} else if (Platform.OS === 'android') {
|
||||
let buttons = [
|
||||
{
|
||||
text: loc.send.details.cancel,
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Choose Photo',
|
||||
onPress: this.choosePhoto,
|
||||
},
|
||||
{
|
||||
text: 'Scan QR Code',
|
||||
onPress: () =>
|
||||
this.props.navigation.navigate('ScanQRCode', {
|
||||
launchedBy: this.props.route.name,
|
||||
onBarScanned: this.onBarCodeRead,
|
||||
showFileImportButton: false,
|
||||
}),
|
||||
},
|
||||
];
|
||||
if (!isClipboardEmpty) {
|
||||
buttons.push({
|
||||
text: 'Copy From Clipboard',
|
||||
onPress: this.copyFromClipbard,
|
||||
});
|
||||
}
|
||||
ActionSheet.showActionSheetWithOptions({
|
||||
title: '',
|
||||
message: '',
|
||||
buttons,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={styles.walletsListWrapper}>
|
||||
{this.renderNavigationHeader()}
|
||||
<SectionList
|
||||
refreshControl={
|
||||
<RefreshControl onRefresh={() => this.refreshTransactions()} refreshing={!this.state.isFlatListRefreshControlHidden} />
|
||||
}
|
||||
refreshControl={<RefreshControl onRefresh={this.refreshTransactions} refreshing={!this.state.isFlatListRefreshControlHidden} />}
|
||||
renderItem={this.renderSectionItem}
|
||||
keyExtractor={this.sectionListKeyExtractor}
|
||||
renderSectionHeader={this.renderSectionHeader}
|
||||
|
|
|
@ -12,12 +12,17 @@ const BlueApp = require('../../BlueApp');
|
|||
const loc = require('../../loc');
|
||||
|
||||
const SelectWallet = () => {
|
||||
const { chainType, onWalletSelect } = useRoute().params;
|
||||
const { chainType, onWalletSelect, availableWallets } = useRoute().params;
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const data = chainType
|
||||
let data = chainType
|
||||
? BlueApp.getWallets().filter(item => item.chain === chainType && item.allowSend())
|
||||
: BlueApp.getWallets().filter(item => item.allowSend()) || [];
|
||||
|
||||
if (availableWallets && availableWallets.length > 0) {
|
||||
// availableWallets if provided, overrides chainType argument and `allowSend()` check
|
||||
data = availableWallets;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
|
|
@ -82,7 +82,7 @@ export default class WalletTransactions extends Component {
|
|||
super(props);
|
||||
|
||||
// here, when we receive REMOTE_TRANSACTIONS_COUNT_CHANGED we fetch TXs and balance for current wallet
|
||||
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED, this.refreshTransactionsFunction.bind(this));
|
||||
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED, this.refreshTransactionsFunction.bind(this), true);
|
||||
const wallet = props.route.params.wallet;
|
||||
this.props.navigation.setParams({ wallet: wallet, isLoading: true });
|
||||
this.state = {
|
||||
|
@ -108,6 +108,7 @@ export default class WalletTransactions extends Component {
|
|||
|
||||
this._unsubscribeFocus = this.props.navigation.addListener('focus', () => {
|
||||
StatusBar.setBarStyle('light-content');
|
||||
if (Platform.OS === 'android') StatusBar.setBackgroundColor(WalletGradient.headerColorFor(this.props.route.params.wallet.type));
|
||||
this.redrawScreen();
|
||||
this.props.navigation.setParams({ isLoading: false });
|
||||
});
|
||||
|
@ -471,6 +472,7 @@ export default class WalletTransactions extends Component {
|
|||
|
||||
onWillBlur() {
|
||||
StatusBar.setBarStyle('dark-content');
|
||||
if (Platform.OS === 'android') StatusBar.setBackgroundColor('#ffffff');
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -546,52 +548,57 @@ export default class WalletTransactions extends Component {
|
|||
this.onBarCodeRead({ data: await Clipboard.getString() });
|
||||
};
|
||||
|
||||
sendButtonLongPress = () => {
|
||||
sendButtonLongPress = async () => {
|
||||
const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0;
|
||||
if (Platform.OS === 'ios') {
|
||||
ActionSheet.showActionSheetWithOptions(
|
||||
{ options: [loc.send.details.cancel, 'Choose Photo', 'Scan QR Code', 'Copy from Clipboard'], cancelButtonIndex: 0 },
|
||||
buttonIndex => {
|
||||
if (buttonIndex === 1) {
|
||||
this.choosePhoto();
|
||||
} else if (buttonIndex === 2) {
|
||||
let options = [loc.send.details.cancel, 'Choose Photo', 'Scan QR Code'];
|
||||
if (!isClipboardEmpty) {
|
||||
options.push('Copy from Clipboard');
|
||||
}
|
||||
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0 }, buttonIndex => {
|
||||
if (buttonIndex === 1) {
|
||||
this.choosePhoto();
|
||||
} else if (buttonIndex === 2) {
|
||||
this.props.navigation.navigate('ScanQRCode', {
|
||||
launchedBy: this.props.route.name,
|
||||
onBarScanned: this.onBarCodeRead,
|
||||
showFileImportButton: false,
|
||||
});
|
||||
} else if (buttonIndex === 3) {
|
||||
this.copyFromClipbard();
|
||||
}
|
||||
});
|
||||
} else if (Platform.OS === 'android') {
|
||||
let buttons = [
|
||||
{
|
||||
text: loc.send.details.cancel,
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Choose Photo',
|
||||
onPress: this.choosePhoto,
|
||||
},
|
||||
{
|
||||
text: 'Scan QR Code',
|
||||
onPress: () =>
|
||||
this.props.navigation.navigate('ScanQRCode', {
|
||||
launchedBy: this.props.route.name,
|
||||
onBarScanned: this.onBarCodeRead,
|
||||
showFileImportButton: false,
|
||||
});
|
||||
} else if (buttonIndex === 3) {
|
||||
this.copyFromClipbard();
|
||||
}
|
||||
}),
|
||||
},
|
||||
);
|
||||
} else if (Platform.OS === 'android') {
|
||||
];
|
||||
if (!isClipboardEmpty) {
|
||||
buttons.push({
|
||||
text: 'Copy From Clipboard',
|
||||
onPress: this.copyFromClipbard,
|
||||
});
|
||||
}
|
||||
ActionSheet.showActionSheetWithOptions({
|
||||
title: '',
|
||||
message: '',
|
||||
buttons: [
|
||||
{
|
||||
text: loc.send.details.cancel,
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Choose Photo',
|
||||
onPress: this.choosePhoto,
|
||||
},
|
||||
{
|
||||
text: 'Scan QR Code',
|
||||
onPress: () =>
|
||||
this.props.navigation.navigate('ScanQRCode', {
|
||||
launchedBy: this.props.route.name,
|
||||
onBarScanned: this.onBarCodeRead,
|
||||
showFileImportButton: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
text: 'Copy From Clipboard',
|
||||
onPress: this.copyFromClipbard,
|
||||
},
|
||||
],
|
||||
buttons,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,8 @@ const branch = require('child_process')
|
|||
.toString()
|
||||
.trim();
|
||||
|
||||
if (branch === 'master') process.exit();
|
||||
|
||||
const req = https.request(
|
||||
{
|
||||
hostname: 'api.github.com',
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
/* global it, describe, expect, element, by, waitFor, device */
|
||||
/* global it, describe, expect, element, by, waitFor, device, jasmine */
|
||||
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const assert = require('assert');
|
||||
const createHash = require('create-hash');
|
||||
|
||||
jasmine.getEnv().addReporter({
|
||||
specStarted: result => (jasmine.currentTest = result),
|
||||
specDone: result => (jasmine.currentTest = result),
|
||||
});
|
||||
|
||||
describe('BlueWallet UI Tests', () => {
|
||||
it('selftest passes', async () => {
|
||||
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
|
||||
if (process.env.TRAVIS) {
|
||||
if (require('fs').existsSync(lockFile))
|
||||
return console.warn('skipping', jasmine.currentTest.fullName, 'as it previously passed on Travis');
|
||||
}
|
||||
await waitFor(element(by.id('WalletsList')))
|
||||
.toBeVisible()
|
||||
.withTimeout(300 * 1000);
|
||||
|
@ -17,9 +28,15 @@ describe('BlueWallet UI Tests', () => {
|
|||
await waitFor(element(by.id('SelfTestOk')))
|
||||
.toBeVisible()
|
||||
.withTimeout(300 * 1000);
|
||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||
});
|
||||
|
||||
it('can create wallet, reload app and it persists', async () => {
|
||||
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
|
||||
if (process.env.TRAVIS) {
|
||||
if (require('fs').existsSync(lockFile))
|
||||
return console.warn('skipping', jasmine.currentTest.fullName, 'as it previously passed on Travis');
|
||||
}
|
||||
await yo('WalletsList');
|
||||
|
||||
await helperCreateWallet();
|
||||
|
@ -27,9 +44,15 @@ describe('BlueWallet UI Tests', () => {
|
|||
await device.launchApp({ newInstance: true });
|
||||
await yo('WalletsList');
|
||||
await expect(element(by.id('cr34t3d'))).toBeVisible();
|
||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||
});
|
||||
|
||||
it('can encrypt storage, with plausible deniability', async () => {
|
||||
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
|
||||
if (process.env.TRAVIS) {
|
||||
if (require('fs').existsSync(lockFile))
|
||||
return console.warn('skipping', jasmine.currentTest.fullName, 'as it previously passed on Travis');
|
||||
}
|
||||
await yo('WalletsList');
|
||||
|
||||
// lets create a wallet
|
||||
|
@ -162,9 +185,15 @@ describe('BlueWallet UI Tests', () => {
|
|||
|
||||
// previously created wallet in FAKE storage should be visible
|
||||
await expect(element(by.id('fake_wallet'))).toBeVisible();
|
||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||
});
|
||||
|
||||
it('can encrypt storage, and decrypt storage works', async () => {
|
||||
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
|
||||
if (process.env.TRAVIS) {
|
||||
if (require('fs').existsSync(lockFile))
|
||||
return console.warn('skipping', jasmine.currentTest.fullName, 'as it previously passed on Travis');
|
||||
}
|
||||
await yo('WalletsList');
|
||||
await helperCreateWallet();
|
||||
await element(by.id('SettingsButton')).tap();
|
||||
|
@ -232,9 +261,15 @@ describe('BlueWallet UI Tests', () => {
|
|||
// relaunch app
|
||||
await device.launchApp({ newInstance: true });
|
||||
await yo('cr34t3d'); // success
|
||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||
});
|
||||
|
||||
it.skip('can encrypt storage, and decrypt storage, but this time the fake one', async () => {
|
||||
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
|
||||
if (process.env.TRAVIS) {
|
||||
if (require('fs').existsSync(lockFile))
|
||||
return console.warn('skipping', jasmine.currentTest.fullName, 'as it previously passed on Travis');
|
||||
}
|
||||
// this test mostly repeats previous one, except in the end it logins with FAKE password to unlock FAKE
|
||||
// storage bucket, and then decrypts it. effectively, everything from MAIN storage bucket is lost
|
||||
if (process.env.TRAVIS) return; // skipping on CI to not take time (plus it randomly fails)
|
||||
|
@ -305,9 +340,15 @@ describe('BlueWallet UI Tests', () => {
|
|||
// relaunch app
|
||||
await device.launchApp({ newInstance: true });
|
||||
await yo('fake_wallet'); // success, we are observing wallet in FAKE storage. wallet from main storage is lost
|
||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||
});
|
||||
|
||||
it('can import BIP84 mnemonic, fetch balance & transactions, then create a transaction', async () => {
|
||||
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
|
||||
if (process.env.TRAVIS) {
|
||||
if (require('fs').existsSync(lockFile))
|
||||
return console.warn('skipping', jasmine.currentTest.fullName, 'as it previously passed on Travis');
|
||||
}
|
||||
if (!process.env.HD_MNEMONIC_BIP84) {
|
||||
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
|
||||
return;
|
||||
|
@ -361,9 +402,15 @@ describe('BlueWallet UI Tests', () => {
|
|||
assert.strictEqual(transaction.outs.length, 2);
|
||||
assert.strictEqual(bitcoin.address.fromOutputScript(transaction.outs[0].script), 'bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl'); // to address
|
||||
assert.strictEqual(transaction.outs[0].value, 10000);
|
||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||
});
|
||||
|
||||
it('can import zpub as watch-only and create PSBT', async () => {
|
||||
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
|
||||
if (process.env.TRAVIS) {
|
||||
if (require('fs').existsSync(lockFile))
|
||||
return console.warn('skipping', jasmine.currentTest.fullName, 'as it previously passed on Travis');
|
||||
}
|
||||
await helperImportWallet(
|
||||
'zpub6r7jhKKm7BAVx3b3nSnuadY1WnshZYkhK8gKFoRLwK9rF3Mzv28BrGcCGA3ugGtawi1WLb2vyjQAX9ZTDGU5gNk2bLdTc3iEXr6tzR1ipNP',
|
||||
'Imported Watch-only',
|
||||
|
@ -381,6 +428,7 @@ describe('BlueWallet UI Tests', () => {
|
|||
} catch (_) {}
|
||||
|
||||
await yo('TextHelperForPSBT');
|
||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -438,3 +486,10 @@ async function helperImportWallet(importText, expectedWalletLabel, expectedBalan
|
|||
// label might change in the future
|
||||
expect(element(by.id('WalletBalance'))).toHaveText(expectedBalance);
|
||||
}
|
||||
|
||||
function hashIt(s) {
|
||||
return createHash('sha256')
|
||||
.update(s)
|
||||
.digest()
|
||||
.toString('hex');
|
||||
}
|
||||
|
|
|
@ -210,6 +210,7 @@ describe('LightningCustodianWallet', () => {
|
|||
|
||||
const api = new Frisbee({
|
||||
baseURI: 'https://api.strike.acinq.co',
|
||||
headers: {},
|
||||
});
|
||||
|
||||
api.auth(process.env.STRIKE + ':');
|
||||
|
|
|
@ -127,6 +127,18 @@ describe('unit - DeepLinkSchemaMatch', function() {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
argument: {
|
||||
url: 'https://azte.co/?c1=3062&c2=2586&c3=5053&c4=5261',
|
||||
},
|
||||
expected: [
|
||||
'AztecoRedeemRoot',
|
||||
{
|
||||
screen: 'AztecoRedeem',
|
||||
params: { c1: '3062', c2: '2586', c3: '5053', c4: '5261', uri: 'https://azte.co/?c1=3062&c2=2586&c3=5053&c4=5261' },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const asyncNavigationRouteFor = async function(event) {
|
||||
|
|
Loading…
Add table
Reference in a new issue