Stop flickering + added loader in AddressSelector (#4149)

* Stop UI flickering + added loader to AddressSelector #4103

* PR Grumbles
This commit is contained in:
Nicolas Gotchac 2017-01-13 15:52:24 +01:00 committed by Jaco Greeff
parent f0eab337d8
commit 57ce845e4c
8 changed files with 107 additions and 28 deletions

View File

@ -220,13 +220,27 @@ export default class TransferStore {
}
@action _attachWalletOperation = (txhash) => {
if (!txhash || /^(0x)?0*$/.test(txhash)) {
return;
}
let ethSubscriptionId = null;
// Number of blocks left to look-up (unsub after 15 blocks if nothing)
let nBlocksLeft = 15;
return this.api.subscribe('eth_blockNumber', () => {
this.api.eth
.getTransactionReceipt(txhash)
.then((tx) => {
if (nBlocksLeft <= 0) {
this.api.unsubscribe(ethSubscriptionId);
ethSubscriptionId = null;
return;
}
if (!tx) {
nBlocksLeft--;
return;
}
@ -239,6 +253,10 @@ export default class TransferStore {
this.operation = operations[0];
}
this.api.unsubscribe(ethSubscriptionId);
ethSubscriptionId = null;
})
.catch(() => {
this.api.unsubscribe(ethSubscriptionId);
ethSubscriptionId = null;
});

View File

@ -27,6 +27,7 @@
transition: transform ease-out 0.1s;
transform: scale(1);
overflow: hidden;
&.copied {
animation-duration: 0.25s;

View File

@ -15,6 +15,22 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.outerInput {
display: flex;
flex-direction: row;
position: relative;
.input {
flex: 1;
}
.loader {
position: absolute;
bottom: 1rem;
right: 9rem;
}
}
.input {
box-sizing: border-box;
appearance: textfield;
@ -58,13 +74,13 @@
}
.label {
margin: 1rem 2.5rem 0.25em;
margin: 1rem 0.5rem 0.25em;
color: rgba(255, 255, 255, 0.498039);
}
.underline {
position: relative;
margin: 0 9rem 0 2.5rem;
margin: 0 0.5rem 0 0.5rem;
}
.empty {
@ -78,7 +94,7 @@
.input {
font-size: 1.5em;
padding: 0 9rem 0.5em 2.5rem;
padding: 0 9rem 0.5em 0.5rem;
display: block;
padding-right: 6rem;
@ -92,7 +108,7 @@
flex-direction: row;
justify-content: flex-start;
margin: 2rem 2rem 0;
margin: 2rem 0 0;
> * {
flex: 1;
@ -107,8 +123,11 @@
.title {
text-transform: uppercase;
font-size: 1.5em;
font-color: white;
h3 {
margin: 0;
}
}
.cards {

View File

@ -25,6 +25,7 @@ import TextFieldUnderline from 'material-ui/TextField/TextFieldUnderline';
import AccountCard from '~/ui/AccountCard';
import InputAddress from '~/ui/Form/InputAddress';
import Loading from '~/ui/Loading';
import Portal from '~/ui/Portal';
import { nodeOrStringProptype } from '~/util/proptypes';
import { validateAddress } from '~/util/validation';
@ -130,7 +131,7 @@ class AddressSelect extends Component {
const input = (
<InputAddress
accountsInfo={ accountsInfo }
allowCopy={ allowCopy }
allowCopy={ (disabled || readOnly) && allowCopy ? allowCopy : false }
className={ className }
disabled={ disabled || readOnly }
error={ error }
@ -182,17 +183,18 @@ class AddressSelect extends Component {
<label className={ styles.label } htmlFor={ id }>
{ label }
</label>
<div className={ styles.outerInput }>
<input
id={ id }
className={ styles.input }
placeholder={ ilHint }
onBlur={ this.handleInputBlur }
onFocus={ this.handleInputFocus }
onChange={ this.handleChange }
ref={ this.setInputRef }
/>
{ this.renderLoader() }
</div>
<div className={ styles.underline }>
<TextFieldUnderline
@ -210,6 +212,19 @@ class AddressSelect extends Component {
);
}
renderLoader () {
if (!this.store.loading) {
return null;
}
return (
<Loading
className={ styles.loader }
size={ 0.5 }
/>
);
}
renderCurrentInput () {
const { inputValue } = this.state;
@ -304,7 +319,9 @@ class AddressSelect extends Component {
return (
<div className={ styles.category } key={ `${key}_${index}` }>
<div className={ styles.title }>{ label }</div>
<div className={ styles.title }>
<h3>{ label }</h3>
</div>
{ content }
</div>
);

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React from 'react';
import { observable, action } from 'mobx';
import { observable, action, transaction } from 'mobx';
import { flatMap, uniqBy } from 'lodash';
import { FormattedMessage } from 'react-intl';
@ -26,6 +26,7 @@ const ZERO = /^(0x)?0*$/;
export default class AddressSelectStore {
@observable loading = false;
@observable values = [];
@observable registryValues = [];
@ -224,21 +225,28 @@ export default class AddressSelectStore {
};
});
// Registries Lookup
// Clear the previous results after 50ms
// if still fetching
const timeoutId = setTimeout(() => {
transaction(() => {
this.registryValues = [];
this.loading = true;
});
}, 50);
const lookups = this.regLookups.map((regLookup) => regLookup(value));
Promise
// Registries Lookup
return Promise
.all(lookups)
.then((results) => {
return results
.filter((result) => result && !ZERO.test(result.address));
})
.then((results) => {
results = uniqBy(results, (result) => result.address);
clearTimeout(timeoutId);
this.registryValues = results
const registryValues = uniqBy(results, (result) => result.address)
.map((result) => {
const lowercaseAddress = result.address.toLowerCase();
@ -253,6 +261,11 @@ export default class AddressSelectStore {
return result;
});
transaction(() => {
this.loading = false;
this.registryValues = registryValues;
});
});
}

View File

@ -76,7 +76,7 @@ class InputAddress extends Component {
const props = {};
if (!readOnly && !disabled) {
if (!disabled) {
props.focused = focused;
}

View File

@ -21,15 +21,22 @@ import styles from './loading.css';
export default class Loading extends Component {
static propTypes = {
className: PropTypes.string,
size: PropTypes.number
};
static defaultProps = {
className: '',
size: 2
};
render () {
const size = (this.props.size || 2) * 60;
const { className, size } = this.props;
const computedSize = size * 60;
return (
<div className={ styles.loading }>
<CircularProgress size={ size } />
<div className={ [ styles.loading, className ].join(' ') }>
<CircularProgress size={ computedSize } />
</div>
);
}

View File

@ -68,6 +68,9 @@ $top: 20vh;
opacity: 0;
z-index: -10;
padding: 1em;
box-sizing: border-box;
* {
min-width: 0;
}
@ -83,6 +86,7 @@ $top: 20vh;
top: 0.5rem;
right: 1rem;
font-size: 4em;
z-index: 100;
transition-property: opacity;
transition-duration: 0.25s;