From 90fc4812bc75857581e56eb6d63484dbc5c48cb1 Mon Sep 17 00:00:00 2001 From: "Clark, Jason (Contractor)" Date: Thu, 23 Nov 2017 18:33:44 -0700 Subject: incremental commit --- .gitignore | 2 ++ app/scripts/controllers/preferences.js | 8 ++++++++ package.json | 10 ++++++---- ui/app/actions.js | 9 +++++++++ ui/app/components/identicon.js | 3 ++- ui/app/reducers/metamask.js | 6 ++++++ ui/app/settings.js | 25 +++++++++++++++++++++++++ 7 files changed, 58 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 08a544449..92b3f2875 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ app/bower_components test/bower_components package +.idea + temp .tmp .sass-cache diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 10004caad..c0454f77b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -14,6 +14,14 @@ class PreferencesController { } // PUBLIC METHODS + toggleUseBlockie () { + this.store.updateState({ useBlockie: !this.useBlockie() }) + } + + getUseBlockie () { + return this.store.getState().useBlockie + } + setSelectedAddress (_address) { return new Promise((resolve, reject) => { const address = normalizeAddress(_address) diff --git a/package.json b/package.json index 12c839739..c0e21ffa7 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "babel-runtime": "^6.23.0", "bignumber.js": "^4.0.4", "bip39": "^2.2.0", + "blockies": "0.0.2", "bluebird": "^3.5.0", "bn.js": "^4.11.7", "boron": "^0.2.3", @@ -77,8 +78,8 @@ "eslint-plugin-react": "^7.4.0", "eth-bin-to-ops": "^1.0.1", "eth-block-tracker": "^2.2.0", - "eth-hd-keyring": "^1.2.1", "eth-contract-metadata": "^1.1.5", + "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.4", "eth-keyring-controller": "^2.1.2", "eth-phishing-detect": "^1.1.4", @@ -101,7 +102,6 @@ "fast-json-patch": "^2.0.4", "fast-levenshtein": "^2.0.6", "fuse.js": "^3.1.0", - "gulp": "github:gulpjs/gulp#4.0", "gulp-autoprefixer": "^4.0.0", "gulp-eslint": "^4.0.0", "gulp-sass": "^3.1.0", @@ -144,12 +144,14 @@ "react-hyperscript": "^3.0.0", "react-markdown": "^2.3.0", "react-redux": "^5.0.5", - "react-select": "^1.0.0-rc.2", + "react-select": "^1.0.0", "react-simple-file-input": "^2.0.0", + "react-toggle": "^4.0.2", + "react-toggle-switch": "^3.0.3", "react-tooltip-component": "^0.3.0", "react-transition-group": "^2.2.0", - "reactify": "^1.1.1", "react-trigger-change": "^1.0.2", + "reactify": "^1.1.1", "readable-stream": "^2.3.3", "recompose": "^0.25.0", "redux": "^3.0.5", diff --git a/ui/app/actions.js b/ui/app/actions.js index 2ca62c41f..957e42223 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -234,6 +234,9 @@ var actions = { toggleAccountMenu, useEtherscanProvider, + + TOGGLE_USE_BLOCKIE: 'TOGGLE_USE_BLOCKIE', + toggleUseBlockie, } module.exports = actions @@ -1550,3 +1553,9 @@ function toggleAccountMenu () { type: actions.TOGGLE_ACCOUNT_MENU, } } + +function toggleUseBlockie () { + return { + type: actions.TOGGLE_USE_BLOCKIE, + } +} diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index d30b7cd56..63f3087a4 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const isNode = require('detect-node') const findDOMNode = require('react-dom').findDOMNode const jazzicon = require('jazzicon') +const blockies = require('blockies') const iconFactoryGen = require('../../lib/icon-factory') const iconFactory = iconFactoryGen(jazzicon) @@ -18,7 +19,7 @@ function IdenticonComponent () { IdenticonComponent.prototype.render = function () { var props = this.props - const { className = '', address } = props + const { className = '', address, useBlockie } = props var diameter = props.diameter || this.defaultDiameter return address diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 83161320e..ee496dc6f 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -36,6 +36,7 @@ function reduceMetamask (state, action) { editingTransactionId: null, }, coinOptions: {}, + useBlockie: false, }, state.metamask) switch (action.type) { @@ -314,6 +315,11 @@ function reduceMetamask (state, action) { coinOptions, }) + case actions.TOGGLE_USE_BLOCKIE: + return extend(metamaskState, { + useBlockie: !metamaskState.useBlockie, + }) + default: return metamaskState diff --git a/ui/app/settings.js b/ui/app/settings.js index 786a70e7e..793906bdb 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -8,6 +8,7 @@ const validUrl = require('valid-url') const { exportAsFile } = require('./util') const TabBar = require('./components/tab-bar') const SimpleDropdown = require('./components/dropdowns/simple-dropdown') +import Switch from 'react-toggle-switch' const getInfuraCurrencyOptions = () => { const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { @@ -51,6 +52,26 @@ class Settings extends Component { ]) } + renderBlockieOptIn () { + const { metamask: { useBlockie }, toggleUseBlockie } = this.props + + return h('div.settings__content-row', [ + h('div.settings__content-item', [ + h('span', 'Use Blockie Identicon'), + ]), + h('div.settings__content-item', [ + h('div.settings__content-item-col', [ + + h(Switch, { + on: useBlockie, + onClick: event => toggleUseBlockie(), + }), + + ]), + ]), + ]) + } + renderCurrentConversion () { const { metamask: { currentCurrency, conversionDate }, setCurrentCurrency } = this.props @@ -214,6 +235,7 @@ class Settings extends Component { return ( h('div.settings__content', [ warning && h('div.settings__error', warning), + this.renderBlockieOptIn(), this.renderCurrentConversion(), // this.renderCurrentProvider(), this.renderNewRpcUrl(), @@ -335,6 +357,7 @@ class Settings extends Component { Settings.propTypes = { tab: PropTypes.string, metamask: PropTypes.object, + useBlockie: PropTypes.bool, setCurrentCurrency: PropTypes.func, setRpcTarget: PropTypes.func, displayWarning: PropTypes.func, @@ -347,6 +370,7 @@ const mapStateToProps = state => { return { metamask: state.metamask, warning: state.appState.warning, + useBlockie: state.useBlockie, } } @@ -357,6 +381,7 @@ const mapDispatchToProps = dispatch => { setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)), displayWarning: warning => dispatch(actions.displayWarning(warning)), revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), + toggleUseBlockie: () => dispatch(actions.toggleUseBlockie()), } } -- cgit v1.2.3 From fc46a16a329df296cb565e3a0b04f268d2aeceb5 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Fri, 24 Nov 2017 10:35:17 -0700 Subject: toggle wired up to preferences property store --- app/scripts/controllers/preferences.js | 4 ++-- app/scripts/metamask-controller.js | 10 ++++++++++ package.json | 9 +++++---- ui/app/actions.js | 23 +++++++++++++++++------ ui/app/reducers/metamask.js | 8 ++++---- ui/app/settings.js | 19 +++++++++---------- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index c0454f77b..7ccb0e730 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -14,8 +14,8 @@ class PreferencesController { } // PUBLIC METHODS - toggleUseBlockie () { - this.store.updateState({ useBlockie: !this.useBlockie() }) + setUseBlockie (val) { + this.store.updateState({ useBlockie: val }) } getUseBlockie () { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index bd71da8e0..3a935d895 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -315,6 +315,7 @@ module.exports = class MetamaskController extends EventEmitter { // etc getState: (cb) => cb(null, this.getState()), setCurrentCurrency: this.setCurrentCurrency.bind(this), + setUseBlockie: this.setUseBlockie.bind(this), markAccountsFound: this.markAccountsFound.bind(this), // coinbase @@ -774,4 +775,13 @@ module.exports = class MetamaskController extends EventEmitter { return rpcTarget } + setUseBlockie(val, cb) { + try { + this.preferencesController.setUseBlockie(val) + cb(null) + } catch (err) { + cb(err) + } + } + } diff --git a/package.json b/package.json index c0e21ffa7..643e7c9a3 100644 --- a/package.json +++ b/package.json @@ -52,11 +52,11 @@ ] }, "dependencies": { - "abi-decoder": "^1.0.8", + "abi-decoder": "^1.0.9", "async": "^2.5.0", "await-semaphore": "^0.1.1", "babel-runtime": "^6.23.0", - "bignumber.js": "^4.0.4", + "bignumber.js": "^4.1.0", "bip39": "^2.2.0", "blockies": "0.0.2", "bluebird": "^3.5.0", @@ -101,7 +101,7 @@ "extensionizer": "^1.0.0", "fast-json-patch": "^2.0.4", "fast-levenshtein": "^2.0.6", - "fuse.js": "^3.1.0", + "fuse.js": "^3.2.0", "gulp-autoprefixer": "^4.0.0", "gulp-eslint": "^4.0.0", "gulp-sass": "^3.1.0", @@ -147,9 +147,10 @@ "react-select": "^1.0.0", "react-simple-file-input": "^2.0.0", "react-toggle": "^4.0.2", + "react-toggle-button": "^2.2.0", "react-toggle-switch": "^3.0.3", "react-tooltip-component": "^0.3.0", - "react-transition-group": "^2.2.0", + "react-transition-group": "^2.2.1", "react-trigger-change": "^1.0.2", "reactify": "^1.1.1", "readable-stream": "^2.3.3", diff --git a/ui/app/actions.js b/ui/app/actions.js index 957e42223..2819742e5 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -235,8 +235,8 @@ var actions = { useEtherscanProvider, - TOGGLE_USE_BLOCKIE: 'TOGGLE_USE_BLOCKIE', - toggleUseBlockie, + SET_USE_BLOCKIE: 'SET_USE_BLOCKIE', + setUseBlockie, } module.exports = actions @@ -1554,8 +1554,19 @@ function toggleAccountMenu () { } } -function toggleUseBlockie () { - return { - type: actions.TOGGLE_USE_BLOCKIE, +function setUseBlockie (val) { + return (dispatch) => { + dispatch(actions.showLoadingIndication()) + log.debug(`background.setUseBlockie`) + background.setUseBlockie(val, (err) => { + dispatch(actions.hideLoadingIndication()) + if (err) { + return dispatch(actions.displayWarning(err.message)) + } + }) + dispatch({ + type: actions.SET_USE_BLOCKIE, + value: val + }) } -} +} \ No newline at end of file diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index ee496dc6f..1b747e188 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -315,10 +315,10 @@ function reduceMetamask (state, action) { coinOptions, }) - case actions.TOGGLE_USE_BLOCKIE: - return extend(metamaskState, { - useBlockie: !metamaskState.useBlockie, - }) + case actions.SET_USE_BLOCKIE: + return extend(metamaskState, { + useBlockie: action.value + }) default: return metamaskState diff --git a/ui/app/settings.js b/ui/app/settings.js index 793906bdb..949cbfb26 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -8,7 +8,7 @@ const validUrl = require('valid-url') const { exportAsFile } = require('./util') const TabBar = require('./components/tab-bar') const SimpleDropdown = require('./components/dropdowns/simple-dropdown') -import Switch from 'react-toggle-switch' +const ToggleButton = require('react-toggle-button') const getInfuraCurrencyOptions = () => { const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { @@ -53,7 +53,7 @@ class Settings extends Component { } renderBlockieOptIn () { - const { metamask: { useBlockie }, toggleUseBlockie } = this.props + const { metamask: { useBlockie }, setUseBlockie } = this.props return h('div.settings__content-row', [ h('div.settings__content-item', [ @@ -61,12 +61,12 @@ class Settings extends Component { ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ - - h(Switch, { - on: useBlockie, - onClick: event => toggleUseBlockie(), + h(ToggleButton, { + value: useBlockie, + onToggle: (value) => setUseBlockie(!value), + activeLabel: '', + inactiveLabel: '', }), - ]), ]), ]) @@ -357,7 +357,7 @@ class Settings extends Component { Settings.propTypes = { tab: PropTypes.string, metamask: PropTypes.object, - useBlockie: PropTypes.bool, + setUseBlockie: PropTypes.func, setCurrentCurrency: PropTypes.func, setRpcTarget: PropTypes.func, displayWarning: PropTypes.func, @@ -370,7 +370,6 @@ const mapStateToProps = state => { return { metamask: state.metamask, warning: state.appState.warning, - useBlockie: state.useBlockie, } } @@ -381,7 +380,7 @@ const mapDispatchToProps = dispatch => { setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)), displayWarning: warning => dispatch(actions.displayWarning(warning)), revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), - toggleUseBlockie: () => dispatch(actions.toggleUseBlockie()), + setUseBlockie: value => dispatch(actions.setUseBlockie(value)), } } -- cgit v1.2.3 From dc7bd3c62897edfb642f215a71fbf7dd93faa350 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Fri, 24 Nov 2017 13:48:56 -0700 Subject: incremental commit of working blockie component --- package.json | 4 +-- ui/app/components/blockies/blockies-component.js | 30 +++++++++++++++++ ui/app/components/identicon.js | 41 +++++++++++++++--------- 3 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 ui/app/components/blockies/blockies-component.js diff --git a/package.json b/package.json index 643e7c9a3..ea1489086 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "babel-runtime": "^6.23.0", "bignumber.js": "^4.1.0", "bip39": "^2.2.0", - "blockies": "0.0.2", "bluebird": "^3.5.0", "bn.js": "^4.11.7", "boron": "^0.2.3", @@ -87,6 +86,7 @@ "eth-sig-util": "^1.4.0", "eth-simple-keyring": "^1.2.0", "eth-token-tracker": "^1.1.4", + "ethereum-blockies": "^0.1.1", "ethereumjs-abi": "^0.6.4", "ethereumjs-tx": "^1.3.0", "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", @@ -146,9 +146,7 @@ "react-redux": "^5.0.5", "react-select": "^1.0.0", "react-simple-file-input": "^2.0.0", - "react-toggle": "^4.0.2", "react-toggle-button": "^2.2.0", - "react-toggle-switch": "^3.0.3", "react-tooltip-component": "^0.3.0", "react-transition-group": "^2.2.1", "react-trigger-change": "^1.0.2", diff --git a/ui/app/components/blockies/blockies-component.js b/ui/app/components/blockies/blockies-component.js new file mode 100644 index 000000000..d6defda16 --- /dev/null +++ b/ui/app/components/blockies/blockies-component.js @@ -0,0 +1,30 @@ +const Component = require('react').Component +const createElement = require('react').createElement +const blockies = require("ethereum-blockies"); + +class BlockiesIdenticon extends Component { + constructor(props) { + super(props); + } + getOpts () { + return { + seed: this.props.seed || "foo", + color: this.props.color || "#dfe", + bgcolor: this.props.bgcolor || "#a71", + size: this.props.size || 15, + scale: this.props.scale || 3, + spotcolor: this.props.spotcolor || "#000" + }; + } + componentDidMount() { + this.draw(); + } + draw() { + blockies.render(this.getOpts(), this.canvas); + } + render() { + return createElement("canvas", {ref: canvas => this.canvas = canvas}); + } +} + +module.exports = BlockiesIdenticon; diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 63f3087a4..9e9b82aae 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -1,14 +1,15 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits +const connect = require('react-redux').connect const isNode = require('detect-node') const findDOMNode = require('react-dom').findDOMNode const jazzicon = require('jazzicon') -const blockies = require('blockies') +const BlockiesIdenticon = require('./blockies/blockies-component') const iconFactoryGen = require('../../lib/icon-factory') const iconFactory = iconFactoryGen(jazzicon) -module.exports = IdenticonComponent +module.exports = connect(mapStateToProps)(IdenticonComponent) inherits(IdenticonComponent, Component) function IdenticonComponent () { @@ -17,6 +18,12 @@ function IdenticonComponent () { this.defaultDiameter = 46 } +function mapStateToProps (state) { + return { + useBlockie: state.metamask.useBlockie + } +} + IdenticonComponent.prototype.render = function () { var props = this.props const { className = '', address, useBlockie } = props @@ -24,19 +31,23 @@ IdenticonComponent.prototype.render = function () { return address ? ( - h('div', { - className: `${className} identicon`, - key: 'identicon-' + address, - style: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - height: diameter, - width: diameter, - borderRadius: diameter / 2, - overflow: 'hidden', - }, - }) + useBlockie + ? h(BlockiesIdenticon, { + seed: address, + }) + : h('div', { + className: `${className} identicon`, + key: 'identicon-' + address, + style: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: diameter, + width: diameter, + borderRadius: diameter / 2, + overflow: 'hidden', + }, + }) ) : ( h('img.balance-icon', { -- cgit v1.2.3 From 41be4714c248870447c7593355f23023d63f24f6 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Fri, 24 Nov 2017 14:18:46 -0700 Subject: tweaking styling --- ui/app/components/blockies/blockies-component.js | 17 +++++++++++------ ui/app/components/identicon.js | 19 ++++++++++++++++--- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/ui/app/components/blockies/blockies-component.js b/ui/app/components/blockies/blockies-component.js index d6defda16..b3a97ced4 100644 --- a/ui/app/components/blockies/blockies-component.js +++ b/ui/app/components/blockies/blockies-component.js @@ -3,25 +3,30 @@ const createElement = require('react').createElement const blockies = require("ethereum-blockies"); class BlockiesIdenticon extends Component { + constructor(props) { super(props); } + getOpts () { return { - seed: this.props.seed || "foo", - color: this.props.color || "#dfe", - bgcolor: this.props.bgcolor || "#a71", - size: this.props.size || 15, - scale: this.props.scale || 3, - spotcolor: this.props.spotcolor || "#000" + seed: this.props.seed, + color: this.props.color, + bgcolor: this.props.bgcolor, + size: this.props.size, + scale: this.props.scale, + spotcolor: this.props.spotcolor, }; } + componentDidMount() { this.draw(); } + draw() { blockies.render(this.getOpts(), this.canvas); } + render() { return createElement("canvas", {ref: canvas => this.canvas = canvas}); } diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 9e9b82aae..c1dc0fb5c 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -32,9 +32,22 @@ IdenticonComponent.prototype.render = function () { return address ? ( useBlockie - ? h(BlockiesIdenticon, { - seed: address, - }) + ? h('div', { + className: `${className} identicon`, + style: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: diameter, + width: diameter, + borderRadius: diameter / 2, + overflow: 'hidden', + }, + }, [ + h(BlockiesIdenticon, { + seed: address + }) + ]) : h('div', { className: `${className} identicon`, key: 'identicon-' + address, -- cgit v1.2.3 From 1b89ceb63aa7d96912eb32c8766ef566479dde41 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Sat, 25 Nov 2017 14:33:42 -0700 Subject: swapped out ethereum-blockies lib for MEW blockies library, tightened up identicon.js code --- package.json | 1 - ui/app/components/blockies/blockies-component.js | 35 --- ui/app/components/identicon.js | 99 +++--- ui/lib/blockies.js | 364 +++++++++++++++++++++++ 4 files changed, 413 insertions(+), 86 deletions(-) delete mode 100644 ui/app/components/blockies/blockies-component.js create mode 100644 ui/lib/blockies.js diff --git a/package.json b/package.json index ea1489086..087ff4ac8 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "eth-sig-util": "^1.4.0", "eth-simple-keyring": "^1.2.0", "eth-token-tracker": "^1.1.4", - "ethereum-blockies": "^0.1.1", "ethereumjs-abi": "^0.6.4", "ethereumjs-tx": "^1.3.0", "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", diff --git a/ui/app/components/blockies/blockies-component.js b/ui/app/components/blockies/blockies-component.js deleted file mode 100644 index b3a97ced4..000000000 --- a/ui/app/components/blockies/blockies-component.js +++ /dev/null @@ -1,35 +0,0 @@ -const Component = require('react').Component -const createElement = require('react').createElement -const blockies = require("ethereum-blockies"); - -class BlockiesIdenticon extends Component { - - constructor(props) { - super(props); - } - - getOpts () { - return { - seed: this.props.seed, - color: this.props.color, - bgcolor: this.props.bgcolor, - size: this.props.size, - scale: this.props.scale, - spotcolor: this.props.spotcolor, - }; - } - - componentDidMount() { - this.draw(); - } - - draw() { - blockies.render(this.getOpts(), this.canvas); - } - - render() { - return createElement("canvas", {ref: canvas => this.canvas = canvas}); - } -} - -module.exports = BlockiesIdenticon; diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index c1dc0fb5c..3e2349dbe 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -5,9 +5,9 @@ const connect = require('react-redux').connect const isNode = require('detect-node') const findDOMNode = require('react-dom').findDOMNode const jazzicon = require('jazzicon') -const BlockiesIdenticon = require('./blockies/blockies-component') const iconFactoryGen = require('../../lib/icon-factory') const iconFactory = iconFactoryGen(jazzicon) +const { toDataUrl } = require('../../lib/blockies') module.exports = connect(mapStateToProps)(IdenticonComponent) @@ -31,36 +31,19 @@ IdenticonComponent.prototype.render = function () { return address ? ( - useBlockie - ? h('div', { - className: `${className} identicon`, - style: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - height: diameter, - width: diameter, - borderRadius: diameter / 2, - overflow: 'hidden', - }, - }, [ - h(BlockiesIdenticon, { - seed: address - }) - ]) - : h('div', { - className: `${className} identicon`, - key: 'identicon-' + address, - style: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - height: diameter, - width: diameter, - borderRadius: diameter / 2, - overflow: 'hidden', - }, - }) + h('div', { + className: `${className} identicon`, + key: useBlockie ? 'blockie' : 'identicon-' + address, + style: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: diameter, + width: diameter, + borderRadius: diameter / 2, + overflow: 'hidden', + }, + }) ) : ( h('img.balance-icon', { @@ -76,38 +59,54 @@ IdenticonComponent.prototype.render = function () { IdenticonComponent.prototype.componentDidMount = function () { var props = this.props - const { address } = props + const { address, useBlockie } = props if (!address) return - // eslint-disable-next-line react/no-find-dom-node - var container = findDOMNode(this) - - var diameter = props.diameter || this.defaultDiameter if (!isNode) { - var img = iconFactory.iconForAddress(address, diameter) - container.appendChild(img) + // eslint-disable-next-line react/no-find-dom-node + var container = findDOMNode(this) + + if (useBlockie) { + _generateBlockie(container, address) + } else { + const diameter = props.diameter || this.defaultDiameter + _generateJazzicon(container, address, diameter) + } } } IdenticonComponent.prototype.componentDidUpdate = function () { var props = this.props - const { address } = props + const { address, useBlockie } = props if (!address) return - // eslint-disable-next-line react/no-find-dom-node - var container = findDOMNode(this) - - var children = container.children - for (var i = 0; i < children.length; i++) { - container.removeChild(children[i]) - } - - var diameter = props.diameter || this.defaultDiameter if (!isNode) { - var img = iconFactory.iconForAddress(address, diameter) - container.appendChild(img) + // eslint-disable-next-line react/no-find-dom-node + var container = findDOMNode(this) + + var children = container.children + for (var i = 0; i < children.length; i++) { + container.removeChild(children[i]) + } + + if (useBlockie) { + _generateBlockie(container, address) + } else { + const diameter = props.diameter || this.defaultDiameter + _generateJazzicon(container, address, diameter) + } } } +function _generateBlockie(container, address) { + const img = new Image() + img.src = toDataUrl(address) + container.appendChild(img) +} + +function _generateJazzicon(container, address, diameter) { + const img = iconFactory.iconForAddress(address, diameter) + container.appendChild(img) +} diff --git a/ui/lib/blockies.js b/ui/lib/blockies.js new file mode 100644 index 000000000..ee5a2a5ca --- /dev/null +++ b/ui/lib/blockies.js @@ -0,0 +1,364 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global.blockies = {}))); +}(this, (function (exports) { 'use strict'; + + /** + * A handy class to calculate color values. + * + * @version 1.0 + * @author Robert Eisele + * @copyright Copyright (c) 2010, Robert Eisele + * @link http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/ + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * + */ + + +// helper functions for that ctx + function write(buffer, offs) { + for (var i = 2; i < arguments.length; i++) { + for (var j = 0; j < arguments[i].length; j++) { + buffer[offs++] = arguments[i].charAt(j); + } + } + } + + function byte2(w) { + return String.fromCharCode((w >> 8) & 255, w & 255); + } + + function byte4(w) { + return String.fromCharCode((w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w & 255); + } + + function byte2lsb(w) { + return String.fromCharCode(w & 255, (w >> 8) & 255); + } + + var PNG = function(width,height,depth) { + + this.width = width; + this.height = height; + this.depth = depth; + + // pixel data and row filter identifier size + this.pix_size = height * (width + 1); + + // deflate header, pix_size, block headers, adler32 checksum + this.data_size = 2 + this.pix_size + 5 * Math.floor((0xfffe + this.pix_size) / 0xffff) + 4; + + // offsets and sizes of Png chunks + this.ihdr_offs = 0; // IHDR offset and size + this.ihdr_size = 4 + 4 + 13 + 4; + this.plte_offs = this.ihdr_offs + this.ihdr_size; // PLTE offset and size + this.plte_size = 4 + 4 + 3 * depth + 4; + this.trns_offs = this.plte_offs + this.plte_size; // tRNS offset and size + this.trns_size = 4 + 4 + depth + 4; + this.idat_offs = this.trns_offs + this.trns_size; // IDAT offset and size + this.idat_size = 4 + 4 + this.data_size + 4; + this.iend_offs = this.idat_offs + this.idat_size; // IEND offset and size + this.iend_size = 4 + 4 + 4; + this.buffer_size = this.iend_offs + this.iend_size; // total PNG size + + this.buffer = new Array(); + this.palette = new Object(); + this.pindex = 0; + + var _crc32 = new Array(); + + // initialize buffer with zero bytes + for (var i = 0; i < this.buffer_size; i++) { + this.buffer[i] = "\x00"; + } + + // initialize non-zero elements + write(this.buffer, this.ihdr_offs, byte4(this.ihdr_size - 12), 'IHDR', byte4(width), byte4(height), "\x08\x03"); + write(this.buffer, this.plte_offs, byte4(this.plte_size - 12), 'PLTE'); + write(this.buffer, this.trns_offs, byte4(this.trns_size - 12), 'tRNS'); + write(this.buffer, this.idat_offs, byte4(this.idat_size - 12), 'IDAT'); + write(this.buffer, this.iend_offs, byte4(this.iend_size - 12), 'IEND'); + + // initialize deflate header + var header = ((8 + (7 << 4)) << 8) | (3 << 6); + header+= 31 - (header % 31); + + write(this.buffer, this.idat_offs + 8, byte2(header)); + + // initialize deflate block headers + for (var i = 0; (i << 16) - 1 < this.pix_size; i++) { + var size, bits; + if (i + 0xffff < this.pix_size) { + size = 0xffff; + bits = "\x00"; + } else { + size = this.pix_size - (i << 16) - i; + bits = "\x01"; + } + write(this.buffer, this.idat_offs + 8 + 2 + (i << 16) + (i << 2), bits, byte2lsb(size), byte2lsb(~size)); + } + + /* Create crc32 lookup table */ + for (var i = 0; i < 256; i++) { + var c = i; + for (var j = 0; j < 8; j++) { + if (c & 1) { + c = -306674912 ^ ((c >> 1) & 0x7fffffff); + } else { + c = (c >> 1) & 0x7fffffff; + } + } + _crc32[i] = c; + } + + // compute the index into a png for a given pixel + this.index = function(x,y) { + var i = y * (this.width + 1) + x + 1; + var j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i; + return j; + }; + + // convert a color and build up the palette + this.color = function(red, green, blue, alpha) { + + alpha = alpha >= 0 ? alpha : 255; + var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue; + + if (typeof this.palette[color] == "undefined") { + if (this.pindex == this.depth) return "\x00"; + + var ndx = this.plte_offs + 8 + 3 * this.pindex; + + this.buffer[ndx + 0] = String.fromCharCode(red); + this.buffer[ndx + 1] = String.fromCharCode(green); + this.buffer[ndx + 2] = String.fromCharCode(blue); + this.buffer[this.trns_offs+8+this.pindex] = String.fromCharCode(alpha); + + this.palette[color] = String.fromCharCode(this.pindex++); + } + return this.palette[color]; + }; + + // output a PNG string, Base64 encoded + this.getBase64 = function() { + + var s = this.getDump(); + + var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var c1, c2, c3, e1, e2, e3, e4; + var l = s.length; + var i = 0; + var r = ""; + + do { + c1 = s.charCodeAt(i); + e1 = c1 >> 2; + c2 = s.charCodeAt(i+1); + e2 = ((c1 & 3) << 4) | (c2 >> 4); + c3 = s.charCodeAt(i+2); + if (l < i+2) { e3 = 64; } else { e3 = ((c2 & 0xf) << 2) | (c3 >> 6); } + if (l < i+3) { e4 = 64; } else { e4 = c3 & 0x3f; } + r+= ch.charAt(e1) + ch.charAt(e2) + ch.charAt(e3) + ch.charAt(e4); + } while ((i+= 3) < l); + return r; + }; + + // output a PNG string + this.getDump = function() { + + // compute adler32 of output pixels + row filter bytes + var BASE = 65521; /* largest prime smaller than 65536 */ + var NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + var s1 = 1; + var s2 = 0; + var n = NMAX; + + for (var y = 0; y < this.height; y++) { + for (var x = -1; x < this.width; x++) { + s1+= this.buffer[this.index(x, y)].charCodeAt(0); + s2+= s1; + if ((n-= 1) == 0) { + s1%= BASE; + s2%= BASE; + n = NMAX; + } + } + } + s1%= BASE; + s2%= BASE; + write(this.buffer, this.idat_offs + this.idat_size - 8, byte4((s2 << 16) | s1)); + + // compute crc32 of the PNG chunks + function crc32(png, offs, size) { + var crc = -1; + for (var i = 4; i < size-4; i += 1) { + crc = _crc32[(crc ^ png[offs+i].charCodeAt(0)) & 0xff] ^ ((crc >> 8) & 0x00ffffff); + } + write(png, offs+size-4, byte4(crc ^ -1)); + } + + crc32(this.buffer, this.ihdr_offs, this.ihdr_size); + crc32(this.buffer, this.plte_offs, this.plte_size); + crc32(this.buffer, this.trns_offs, this.trns_size); + crc32(this.buffer, this.idat_offs, this.idat_size); + crc32(this.buffer, this.iend_offs, this.iend_size); + + // convert PNG to string + return "\x89PNG\r\n\x1A\n"+this.buffer.join(''); + }; + + this.fillRect = function (x, y, w, h, color) { + for(var i = 0; i < w; i++) { + for (var j = 0; j < h; j++) { + this.buffer[this.index(x+i, y+j)] = color; + } + } + }; + }; + +// https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. + * + * @param {number} h The hue + * @param {number} s The saturation + * @param {number} l The lightness + * @return {Array} The RGB representation + */ + + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + function hsl2rgb(h, s, l){ + var r, g, b; + + if(s == 0){ + r = g = b = l; // achromatic + }else{ + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), 255]; + } + +// The random number is a js implementation of the Xorshift PRNG + var randseed = new Array(4); // Xorshift: [x, y, z, w] 32 bit values + + function seedrand(seed) { + for (var i = 0; i < randseed.length; i++) { + randseed[i] = 0; + } + for (var i = 0; i < seed.length; i++) { + randseed[i % 4] = (randseed[i % 4] << 5) - randseed[i % 4] + seed.charCodeAt(i); + } + } + + function rand() { + // based on Java's String.hashCode(), expanded to 4 32bit values + var t = randseed[0] ^ (randseed[0] << 11); + + randseed[0] = randseed[1]; + randseed[1] = randseed[2]; + randseed[2] = randseed[3]; + randseed[3] = randseed[3] ^ (randseed[3] >> 19) ^ t ^ (t >> 8); + + return (randseed[3] >>> 0) / (1 << 31 >>> 0); + } + + function createColor() { + //saturation is the whole color spectrum + var h = Math.floor(rand() * 360); + //saturation goes from 40 to 100, it avoids greyish colors + var s = rand() * 60 + 40; + //lightness can be anything from 0 to 100, but probabilities are a bell curve around 50% + var l = (rand() + rand() + rand() + rand()) * 25; + + return [h / 360,s / 100,l / 100]; + } + + function createImageData(size) { + var width = size; // Only support square icons for now + var height = size; + + var dataWidth = Math.ceil(width / 2); + var mirrorWidth = width - dataWidth; + + var data = []; + for (var y = 0; y < height; y++) { + var row = []; + for (var x = 0; x < dataWidth; x++) { + // this makes foreground and background color to have a 43% (1/2.3) probability + // spot color has 13% chance + row[x] = Math.floor(rand() * 2.3); + } + var r = row.slice(0, mirrorWidth); + r.reverse(); + row = row.concat(r); + + for (var i = 0; i < row.length; i++) { + data.push(row[i]); + } + } + + return data; + } + + function buildOpts(opts) { + if (!opts.seed) { + throw 'No seed provided' + } + + seedrand(opts.seed); + + return Object.assign({ + size: 8, + scale: 16, + color: createColor(), + bgcolor: createColor(), + spotcolor: createColor(), + }, opts) + } + + function toDataUrl(address) { + const opts = buildOpts({seed: address.toLowerCase()}); + + const imageData = createImageData(opts.size); + const width = Math.sqrt(imageData.length); + + const p = new PNG(opts.size*opts.scale, opts.size*opts.scale, 3); + const bgcolor = p.color(...hsl2rgb(...opts.bgcolor)); + const color = p.color(...hsl2rgb(...opts.color)); + const spotcolor = p.color(...hsl2rgb(...opts.spotcolor)); + + for (var i = 0; i < imageData.length; i++) { + var row = Math.floor(i / width); + var col = i % width; + // if data is 0, leave the background + if (imageData[i]) { + // if data is 2, choose spot color, if 1 choose foreground + const pngColor = imageData[i] == 1 ? color : spotcolor; + p.fillRect(col * opts.scale, row * opts.scale, opts.scale, opts.scale, pngColor); + } + } + return `data:image/png;base64,${p.getBase64()}`; + } + + exports.toDataUrl = toDataUrl; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); -- cgit v1.2.3 From bd48d858f4226da889760e259377637164f3099c Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Sat, 25 Nov 2017 15:11:29 -0700 Subject: fixing blockies display issues --- ui/app/components/identicon.js | 12 ++++++++---- ui/app/settings.js | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 3e2349dbe..7a3bd5394 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -67,10 +67,11 @@ IdenticonComponent.prototype.componentDidMount = function () { // eslint-disable-next-line react/no-find-dom-node var container = findDOMNode(this) + const diameter = props.diameter || this.defaultDiameter + if (useBlockie) { _generateBlockie(container, address) } else { - const diameter = props.diameter || this.defaultDiameter _generateJazzicon(container, address, diameter) } } @@ -91,18 +92,21 @@ IdenticonComponent.prototype.componentDidUpdate = function () { container.removeChild(children[i]) } + const diameter = props.diameter || this.defaultDiameter + if (useBlockie) { - _generateBlockie(container, address) + _generateBlockie(container, address, diameter) } else { - const diameter = props.diameter || this.defaultDiameter _generateJazzicon(container, address, diameter) } } } -function _generateBlockie(container, address) { +function _generateBlockie(container, address, diameter) { const img = new Image() img.src = toDataUrl(address) + const dia = !diameter || diameter < 50 ? 50 : diameter + img.height, img.width = dia * 1.25 container.appendChild(img) } diff --git a/ui/app/settings.js b/ui/app/settings.js index 949cbfb26..caa36d2b8 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -57,7 +57,7 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', 'Use Blockie Identicon'), + h('span', 'Use Blockies Identicon'), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ -- cgit v1.2.3 From 75ef848196646e060703764e97656ab3abd8c023 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Sat, 25 Nov 2017 15:47:34 -0700 Subject: making eslint happy --- ui/app/actions.js | 4 ++-- ui/app/components/identicon.js | 9 +++++---- ui/app/reducers/metamask.js | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/app/actions.js b/ui/app/actions.js index 2819742e5..e79f4373e 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1566,7 +1566,7 @@ function setUseBlockie (val) { }) dispatch({ type: actions.SET_USE_BLOCKIE, - value: val + value: val, }) } -} \ No newline at end of file +} diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 7a3bd5394..5b3786992 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -20,7 +20,7 @@ function IdenticonComponent () { function mapStateToProps (state) { return { - useBlockie: state.metamask.useBlockie + useBlockie: state.metamask.useBlockie, } } @@ -102,15 +102,16 @@ IdenticonComponent.prototype.componentDidUpdate = function () { } } -function _generateBlockie(container, address, diameter) { +function _generateBlockie (container, address, diameter) { const img = new Image() img.src = toDataUrl(address) const dia = !diameter || diameter < 50 ? 50 : diameter - img.height, img.width = dia * 1.25 + img.height = dia * 1.25 + img.width = dia * 1.25 container.appendChild(img) } -function _generateJazzicon(container, address, diameter) { +function _generateJazzicon (container, address, diameter) { const img = iconFactory.iconForAddress(address, diameter) container.appendChild(img) } diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 1b747e188..fb53bbaef 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -317,7 +317,7 @@ function reduceMetamask (state, action) { case actions.SET_USE_BLOCKIE: return extend(metamaskState, { - useBlockie: action.value + useBlockie: action.value, }) default: -- cgit v1.2.3 From 6f5c32b7cee26b6393e2a9dfdeb8bf4d63c18b49 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Sat, 25 Nov 2017 15:52:46 -0700 Subject: adding blockies lib to eslint ignore so it doesn't blow up the style checker and fail the build --- .eslintignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index b96f79011..a73bb2ffd 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,5 @@ app/scripts/lib/extension-instance.js test/integration/bundle.js test/integration/jquery-3.1.0.min.js test/integration/helpers.js -test/integration/lib/first-time.js \ No newline at end of file +test/integration/lib/first-time.js +ui/app/lib/blockies.js \ No newline at end of file -- cgit v1.2.3 From abefcc9612d75067474e521486d62684dfeae9c7 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Sat, 25 Nov 2017 15:57:54 -0700 Subject: more eslint fixes --- .eslintignore | 2 +- app/scripts/metamask-controller.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintignore b/.eslintignore index a73bb2ffd..e4cade21c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,4 +3,4 @@ test/integration/bundle.js test/integration/jquery-3.1.0.min.js test/integration/helpers.js test/integration/lib/first-time.js -ui/app/lib/blockies.js \ No newline at end of file +ui/lib/blockies.js \ No newline at end of file diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 3a935d895..4dce89e3a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -775,7 +775,7 @@ module.exports = class MetamaskController extends EventEmitter { return rpcTarget } - setUseBlockie(val, cb) { + setUseBlockie (val, cb) { try { this.preferencesController.setUseBlockie(val) cb(null) -- cgit v1.2.3 From a34362b7765f48d24375c9953fa7c49cf3306491 Mon Sep 17 00:00:00 2001 From: Jason Clark Date: Mon, 27 Nov 2017 08:11:48 -0700 Subject: Fixes changes requested in pullrequestreview-79088534 --- app/scripts/controllers/preferences.js | 1 + package.json | 1 + ui/app/components/identicon.js | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 7ccb0e730..0aed4dbdf 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -9,6 +9,7 @@ class PreferencesController { frequentRpcList: [], currentAccountTab: 'history', tokens: [], + useBlockie: false, }, opts.initState) this.store = new ObservableStore(initState) } diff --git a/package.json b/package.json index 087ff4ac8..62ee7c0d3 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "fast-levenshtein": "^2.0.6", "fuse.js": "^3.2.0", "gulp-autoprefixer": "^4.0.0", + "gulp": "github:gulpjs/gulp#4.0", "gulp-eslint": "^4.0.0", "gulp-sass": "^3.1.0", "hat": "0.0.3", diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 5b3786992..ddd7e65f3 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -33,7 +33,7 @@ IdenticonComponent.prototype.render = function () { ? ( h('div', { className: `${className} identicon`, - key: useBlockie ? 'blockie' : 'identicon-' + address, + key: 'identicon-' + address, style: { display: 'flex', alignItems: 'center', @@ -70,7 +70,7 @@ IdenticonComponent.prototype.componentDidMount = function () { const diameter = props.diameter || this.defaultDiameter if (useBlockie) { - _generateBlockie(container, address) + _generateBlockie(container, address, diameter) } else { _generateJazzicon(container, address, diameter) } -- cgit v1.2.3 From f131468353aa518b8fc178cd591bfc7ab5bdc32c Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Tue, 28 Nov 2017 13:37:45 -0600 Subject: Remove useBlockie in props for render Removed unused useBlock for Lint validation. --- ui/app/components/identicon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index ddd7e65f3..b803b7ceb 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -26,7 +26,7 @@ function mapStateToProps (state) { IdenticonComponent.prototype.render = function () { var props = this.props - const { className = '', address, useBlockie } = props + const { className = '', address } = props var diameter = props.diameter || this.defaultDiameter return address -- cgit v1.2.3