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) => { @action _attachWalletOperation = (txhash) => {
if (!txhash || /^(0x)?0*$/.test(txhash)) {
return;
}
let ethSubscriptionId = null; 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', () => { return this.api.subscribe('eth_blockNumber', () => {
this.api.eth this.api.eth
.getTransactionReceipt(txhash) .getTransactionReceipt(txhash)
.then((tx) => { .then((tx) => {
if (nBlocksLeft <= 0) {
this.api.unsubscribe(ethSubscriptionId);
ethSubscriptionId = null;
return;
}
if (!tx) { if (!tx) {
nBlocksLeft--;
return; return;
} }
@ -239,6 +253,10 @@ export default class TransferStore {
this.operation = operations[0]; this.operation = operations[0];
} }
this.api.unsubscribe(ethSubscriptionId);
ethSubscriptionId = null;
})
.catch(() => {
this.api.unsubscribe(ethSubscriptionId); this.api.unsubscribe(ethSubscriptionId);
ethSubscriptionId = null; ethSubscriptionId = null;
}); });

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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