From 57ce845e4c91c262cf542bf350a947c40f9b2a92 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 13 Jan 2017 15:52:24 +0100 Subject: [PATCH] Stop flickering + added loader in AddressSelector (#4149) * Stop UI flickering + added loader to AddressSelector #4103 * PR Grumbles --- js/src/modals/Transfer/store.js | 18 ++++++++ js/src/ui/AccountCard/accountCard.css | 1 + .../ui/Form/AddressSelect/addressSelect.css | 29 ++++++++++--- js/src/ui/Form/AddressSelect/addressSelect.js | 43 +++++++++++++------ .../Form/AddressSelect/addressSelectStore.js | 25 ++++++++--- js/src/ui/Form/InputAddress/inputAddress.js | 2 +- js/src/ui/Loading/loading.js | 13 ++++-- js/src/ui/Portal/portal.css | 4 ++ 8 files changed, 107 insertions(+), 28 deletions(-) diff --git a/js/src/modals/Transfer/store.js b/js/src/modals/Transfer/store.js index 9da9023f1..63a29c9a1 100644 --- a/js/src/modals/Transfer/store.js +++ b/js/src/modals/Transfer/store.js @@ -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; }); diff --git a/js/src/ui/AccountCard/accountCard.css b/js/src/ui/AccountCard/accountCard.css index 5820ddf2f..c5e828d97 100644 --- a/js/src/ui/AccountCard/accountCard.css +++ b/js/src/ui/AccountCard/accountCard.css @@ -27,6 +27,7 @@ transition: transform ease-out 0.1s; transform: scale(1); + overflow: hidden; &.copied { animation-duration: 0.25s; diff --git a/js/src/ui/Form/AddressSelect/addressSelect.css b/js/src/ui/Form/AddressSelect/addressSelect.css index 25fb67f1c..d24332016 100644 --- a/js/src/ui/Form/AddressSelect/addressSelect.css +++ b/js/src/ui/Form/AddressSelect/addressSelect.css @@ -15,6 +15,22 @@ /* along with Parity. If not, see . */ +.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 { diff --git a/js/src/ui/Form/AddressSelect/addressSelect.js b/js/src/ui/Form/AddressSelect/addressSelect.js index 7b09b5b07..6a71e4245 100644 --- a/js/src/ui/Form/AddressSelect/addressSelect.js +++ b/js/src/ui/Form/AddressSelect/addressSelect.js @@ -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 = ( { label } - +
+ + { this.renderLoader() } +
+ ); + } + renderCurrentInput () { const { inputValue } = this.state; @@ -304,7 +319,9 @@ class AddressSelect extends Component { return (
-
{ label }
+
+

{ label }

+
{ content }
); diff --git a/js/src/ui/Form/AddressSelect/addressSelectStore.js b/js/src/ui/Form/AddressSelect/addressSelectStore.js index e04f8b55d..5025564a0 100644 --- a/js/src/ui/Form/AddressSelect/addressSelectStore.js +++ b/js/src/ui/Form/AddressSelect/addressSelectStore.js @@ -15,7 +15,7 @@ // along with Parity. If not, see . 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 - this.registryValues = []; + // 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; + }); }); } diff --git a/js/src/ui/Form/InputAddress/inputAddress.js b/js/src/ui/Form/InputAddress/inputAddress.js index 3cdac2a2e..4673634c8 100644 --- a/js/src/ui/Form/InputAddress/inputAddress.js +++ b/js/src/ui/Form/InputAddress/inputAddress.js @@ -76,7 +76,7 @@ class InputAddress extends Component { const props = {}; - if (!readOnly && !disabled) { + if (!disabled) { props.focused = focused; } diff --git a/js/src/ui/Loading/loading.js b/js/src/ui/Loading/loading.js index 507c84bf9..6e8faaf8e 100644 --- a/js/src/ui/Loading/loading.js +++ b/js/src/ui/Loading/loading.js @@ -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 ( -
- +
+
); } diff --git a/js/src/ui/Portal/portal.css b/js/src/ui/Portal/portal.css index 65c3b0103..37c57b712 100644 --- a/js/src/ui/Portal/portal.css +++ b/js/src/ui/Portal/portal.css @@ -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;