Skip to content

Commit

Permalink
Remember recent addresses (#597)
Browse files Browse the repository at this point in the history
* kinda works

* keyboard wizardry working

* fix eth input
  • Loading branch information
Bruno Barbieri authored Apr 10, 2019
1 parent f2842e5 commit b730a0f
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 30 deletions.
82 changes: 67 additions & 15 deletions app/components/UI/AccountInput/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import React, { Component } from 'react';
import Icon from 'react-native-vector-icons/FontAwesome';
import Identicon from '../Identicon';
import PropTypes from 'prop-types';
import { Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { ScrollView, Platform, StyleSheet, Text, TextInput, TouchableOpacity, View, Keyboard } from 'react-native';
import { colors, fontStyles } from '../../../styles/common';
import { connect } from 'react-redux';
import { renderShortAddress } from '../../../util/address';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import { ScrollView } from 'react-native-gesture-handler';
import ElevatedView from 'react-native-elevated-view';
import ENS from 'ethjs-ens';
import networkMap from 'ethjs-ens/lib/network-map.json';
import Engine from '../../../core/Engine';
import { strings } from '../../../../locales/i18n';
import AppConstants from '../../../core/AppConstants';
import { isValidAddress } from 'ethereumjs-util';

const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';

Expand Down Expand Up @@ -74,6 +74,9 @@ const styles = StyleSheet.create({
...fontStyles.normal,
fontSize: 16
},
accountWithoutName: {
marginTop: 4
},
name: {
flex: 1,
...fontStyles.bold,
Expand Down Expand Up @@ -161,7 +164,11 @@ class AccountInput extends Component {
/**
* Whether accounts dropdown is opened
*/
isOpen: PropTypes.bool
isOpen: PropTypes.bool,
/**
* Map representing the address book
*/
addressBook: PropTypes.array
};

state = {
Expand Down Expand Up @@ -229,26 +236,39 @@ class AccountInput extends Component {
};

selectAccount(account) {
Keyboard.dismiss();
this.onChange(account.address);
const { openAccountSelect } = this.props;
openAccountSelect && openAccountSelect(false);
}

getNetworkEnsSupport = () => {
const { network } = this.props;
return Boolean(networkMap[network]);
};

renderAccountName(name) {
if (name !== '') {
return (
<View>
<Text numberOfLines={1} style={styles.name}>
{name}
</Text>
</View>
);
}

return <View style={styles.accountWithoutName} />;
}

renderOption(account, onPress) {
return (
<TouchableOpacity key={account.address} onPress={onPress} style={styles.option}>
<View style={styles.icon}>
<Identicon address={account.address} diameter={22} />
</View>
<View style={styles.content}>
<View>
<Text numberOfLines={1} style={styles.name}>
{account.name}
</Text>
</View>
{this.renderAccountName(account.name)}
<View>
<Text style={styles.address} numberOfLines={1}>
{renderShortAddress(account.address)}
Expand All @@ -259,11 +279,43 @@ class AccountInput extends Component {
);
}

getVisibleOptions = value => {
const { accounts, addressBook } = this.props;
const addressBookItems = {};
if (addressBook.length > 0) {
addressBook.forEach(contact => {
addressBookItems[contact.address] = contact;
});
}

const allAddresses = { ...addressBookItems, ...accounts };

if (typeof value !== 'undefined' && value.toString().length > 0) {
// If it's a valid address we don't show any suggestion
if (isValidAddress(value)) {
return allAddresses;
}

const filteredAddresses = {};
Object.keys(allAddresses).forEach(address => {
if (
address.toLowerCase().indexOf(value.toLowerCase()) !== -1 ||
(allAddresses[address].name &&
allAddresses[address].name.toLowerCase().indexOf(value.toLowerCase()) !== -1)
) {
filteredAddresses[address] = allAddresses[address];
}
});
return filteredAddresses;
}
return allAddresses;
};

renderOptionList() {
const { visibleOptions = this.props.accounts } = this.state;
const visibleOptions = this.getVisibleOptions(this.state.value);
return (
<ElevatedView elevation={10}>
<ScrollView style={styles.componentContainer}>
<ScrollView style={styles.componentContainer} keyboardShouldPersistTaps={'handled'}>
<View style={styles.optionList}>
{Object.keys(visibleOptions).map(address =>
this.renderOption(visibleOptions[address], () => {
Expand All @@ -277,14 +329,13 @@ class AccountInput extends Component {
}

onChange = async value => {
const { accounts, onChange, openAccountSelect } = this.props;
const addresses = Object.keys(accounts).filter(address => address.toLowerCase().match(value.toLowerCase()));
const visibleOptions = value.length === 0 ? accounts : addresses.map(address => accounts[address]);
const match = visibleOptions.length === 1 && visibleOptions[0].address.toLowerCase() === value.toLowerCase();
const { onChange, openAccountSelect } = this.props;
this.setState({
value
});
openAccountSelect && openAccountSelect((value.length === 0 || visibleOptions.length) > 0 && !match);

const filteredAccounts = this.getVisibleOptions(value);
openAccountSelect && openAccountSelect(Object.keys(filteredAccounts).length > 0);
onChange && onChange(value);
};

Expand Down Expand Up @@ -343,6 +394,7 @@ class AccountInput extends Component {
}

const mapStateToProps = state => ({
addressBook: state.engine.backgroundState.AddressBookController.addressBook,
accounts: state.engine.backgroundState.PreferencesController.identities,
activeAddress: state.engine.backgroundState.PreferencesController.activeAddress,
network: state.engine.backgroundState.NetworkController.network
Expand Down
2 changes: 2 additions & 0 deletions app/components/UI/ActionView/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ exports[`ActionView should render correctly 1`] = `
extraHeight={75}
extraScrollHeight={0}
keyboardOpeningTime={250}
keyboardShouldPersistTaps="never"
resetScrollToCoords={
Object {
"x": 0,
Expand All @@ -29,6 +30,7 @@ exports[`ActionView should render correctly 1`] = `
viewIsInsideTabBar={false}
>
<TouchableWithoutFeedback
onPress={[Function]}
style={
Object {
"flex": 1,
Expand Down
28 changes: 23 additions & 5 deletions app/components/UI/ActionView/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import StyledButton from '../StyledButton';
import PropTypes from 'prop-types';
import { StyleSheet, View, ActivityIndicator, TouchableWithoutFeedback } from 'react-native';
import { Keyboard, StyleSheet, View, ActivityIndicator, TouchableWithoutFeedback } from 'react-native';
import { baseStyles, colors } from '../../../styles/common';
import { strings } from '../../../../locales/i18n';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
Expand Down Expand Up @@ -41,12 +41,26 @@ export default function ActionView({
showCancelButton,
showConfirmButton,
confirmed,
confirmDisabled
confirmDisabled,
keyboardShouldPersistTaps = 'never'
}) {
return (
<View style={baseStyles.flexGrow}>
<KeyboardAwareScrollView style={baseStyles.flexGrow} resetScrollToCoords={{ x: 0, y: 0 }}>
<TouchableWithoutFeedback style={baseStyles.flexGrow} onPress={onTouchablePress}>
<KeyboardAwareScrollView
style={baseStyles.flexGrow}
resetScrollToCoords={{ x: 0, y: 0 }}
keyboardShouldPersistTaps={keyboardShouldPersistTaps}
>
<TouchableWithoutFeedback
style={baseStyles.flexGrow}
// eslint-disable-next-line react/jsx-no-bind
onPress={() => {
if (keyboardShouldPersistTaps === 'handled') {
Keyboard.dismiss();
}
onTouchablePress();
}}
>
{children}
</TouchableWithoutFeedback>
</KeyboardAwareScrollView>
Expand Down Expand Up @@ -142,5 +156,9 @@ ActionView.propTypes = {
/**
* Whether confirm button is shown
*/
showConfirmButton: PropTypes.bool
showConfirmButton: PropTypes.bool,
/**
* Determines if the keyboard should stay visible after a tap
*/
keyboardShouldPersistTaps: PropTypes.string
};
6 changes: 3 additions & 3 deletions app/components/UI/EthInput/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Platform, StyleSheet, Text, TextInput, View, Image } from 'react-native';
import { Keyboard, ScrollView, Platform, StyleSheet, Text, TextInput, View, Image } from 'react-native';
import { colors, fontStyles } from '../../../styles/common';
import { connect } from 'react-redux';
import {
Expand All @@ -13,7 +13,6 @@ import {
import { strings } from '../../../../locales/i18n';
import TokenImage from '../TokenImage';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import { ScrollView } from 'react-native-gesture-handler';
import ElevatedView from 'react-native-elevated-view';
import CollectibleImage from '../CollectibleImage';
import SelectableAsset from './SelectableAsset';
Expand Down Expand Up @@ -244,6 +243,7 @@ class EthInput extends Component {
};

selectAsset = async asset => {
Keyboard.dismiss();
const { handleUpdateAsset, onChange, openEthInput } = this.props;
openEthInput && openEthInput(false);
handleUpdateAsset && (await handleUpdateAsset(asset));
Expand Down Expand Up @@ -290,7 +290,7 @@ class EthInput extends Component {
const assetsList = assetsLists[assetType]();
return (
<ElevatedView elevation={10} style={styles.root}>
<ScrollView style={styles.componentContainer}>
<ScrollView style={styles.componentContainer} keyboardShouldPersistTaps={'handled'}>
<View style={styles.optionList}>
{assetsList.map(asset => (
<View
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ exports[`TransactionEdit should render correctly 1`] = `
confirmTestID=""
confirmText="Next"
confirmed={false}
keyboardShouldPersistTaps="handled"
onConfirmPress={[Function]}
onTouchablePress={[Function]}
showCancelButton={true}
Expand Down
1 change: 1 addition & 0 deletions app/components/UI/TransactionEdit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ class TransactionEdit extends Component {
onCancelPress={this.props.onCancel}
onConfirmPress={this.review}
onTouchablePress={this.closeDropdowns}
keyboardShouldPersistTaps={'handled'}
>
<View style={styles.form}>
<View style={[styles.formRow, styles.fromRow]}>
Expand Down
20 changes: 16 additions & 4 deletions app/components/Views/Approval/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ class Approval extends Component {
/**
* List of transactions
*/
transactions: PropTypes.array
transactions: PropTypes.array,
/**
* Map representing the address book
*/
addressBook: PropTypes.array
};

state = {
Expand Down Expand Up @@ -78,13 +82,20 @@ class Approval extends Component {
* Callback on confirm transaction
*/
onConfirm = async () => {
const { TransactionController } = Engine.context;
const { transactions } = this.props;
const { TransactionController, AddressBookController } = Engine.context;
const { transactions, addressBook } = this.props;
let { transaction } = this.props;
try {
transaction = this.prepareTransaction(transaction);

TransactionController.hub.once(`${transaction.id}:finished`, transactionMeta => {
// Add to the AddressBook if it's an unkonwn address
const checksummedAddress = toChecksumAddress(transactionMeta.transaction.to);
const existingContact = addressBook.find(address => toChecksumAddress(address) === checksummedAddress);
if (!existingContact) {
AddressBookController.set(checksummedAddress, '');
}

if (transactionMeta.status === 'submitted') {
this.setState({ transactionHandled: true });
this.props.navigation.pop();
Expand Down Expand Up @@ -165,7 +176,8 @@ class Approval extends Component {

const mapStateToProps = state => ({
transaction: state.transaction,
transactions: state.engine.backgroundState.TransactionController.transactions
transactions: state.engine.backgroundState.TransactionController.transactions,
addressBook: state.engine.backgroundState.AddressBookController.addressBook
});

const mapDispatchToProps = dispatch => ({
Expand Down
3 changes: 3 additions & 0 deletions app/components/Views/Approval/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ describe('Approval', () => {
backgroundState: {
TransactionController: {
transactions: []
},
AddressBookController: {
addressBook: []
}
}
}
Expand Down
20 changes: 17 additions & 3 deletions app/components/Views/Send/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ class Send extends Component {
/**
/* Triggers global alert
*/
showAlert: PropTypes.func
showAlert: PropTypes.func,
/**
* Map representing the address book
*/
addressBook: PropTypes.array
};

state = {
Expand Down Expand Up @@ -346,10 +350,11 @@ class Send extends Component {
* and returns to edit transaction
*/
onConfirm = async () => {
const { TransactionController } = Engine.context;
const { TransactionController, AddressBookController } = Engine.context;
this.setState({ transactionConfirmed: true });
const {
transaction: { selectedAsset, assetType }
transaction: { selectedAsset, assetType },
addressBook
} = this.props;
let { transaction } = this.props;
try {
Expand All @@ -361,6 +366,14 @@ class Send extends Component {
const { result, transactionMeta } = await TransactionController.addTransaction(transaction);

await TransactionController.approveTransaction(transactionMeta.id);

// Add to the AddressBook if it's an unkonwn address
const checksummedAddress = toChecksumAddress(transactionMeta.transaction.to);
const existingContact = addressBook.find(address => toChecksumAddress(address) === checksummedAddress);
if (!existingContact) {
AddressBookController.set(checksummedAddress, '');
}

await new Promise(resolve => {
resolve(result);
});
Expand Down Expand Up @@ -418,6 +431,7 @@ class Send extends Component {
}

const mapStateToProps = state => ({
addressBook: state.engine.backgroundState.AddressBookController.addressBook,
accounts: state.engine.backgroundState.AccountTrackerController.accounts,
contractBalances: state.engine.backgroundState.TokenBalancesController.contractBalances,
transaction: state.transaction,
Expand Down
2 changes: 2 additions & 0 deletions app/core/Engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ export default {
get state() {
const {
AccountTrackerController,
AddressBookController,
AssetsContractController,
AssetsController,
AssetsDetectionController,
Expand All @@ -373,6 +374,7 @@ export default {

return {
AccountTrackerController,
AddressBookController,
AssetsContractController,
AssetsController,
AssetsDetectionController,
Expand Down

0 comments on commit b730a0f

Please sign in to comment.