diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | ui/app/account-detail.js | 112 | ||||
-rw-r--r-- | ui/app/actions.js | 1 | ||||
-rw-r--r-- | ui/app/app.js | 3 | ||||
-rw-r--r-- | ui/app/components/account-export.js | 87 | ||||
-rw-r--r-- | ui/app/components/transaction-list.js | 2 | ||||
-rw-r--r-- | ui/app/css/transitions.css | 1 | ||||
-rw-r--r-- | ui/app/reducers/app.js | 19 |
8 files changed, 158 insertions, 70 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 47cd69897..c3c51936e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## Current Master - Add support for calls to `eth.sign`. +- Moved account exporting within transitioning subview on the account detail view. +- Added buttons to the account export process. +- Improved visual appearance of account detail transition where button heights would change. ## 1.7.0 2016-04-29 diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index a876b275f..c93eef4fd 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -1,11 +1,15 @@ const inherits = require('util').inherits +const extend = require('xtend') const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const copyToClipboard = require('copy-to-clipboard') const actions = require('./actions') +const ReactCSSTransitionGroup = require('react-addons-css-transition-group') + const AccountPanel = require('./components/account-panel') const transactionList = require('./components/transaction-list') +const ExportAccountView = require('./components/account-export') module.exports = connect(mapStateToProps)(AccountDetailScreen) @@ -35,7 +39,11 @@ AccountDetailScreen.prototype.render = function() { return ( - h('.account-detail-section.flex-column.flex-grow', [ + h('.account-detail-section.flex-column.flex-grow', { + style: { + width: '330px', + }, + }, [ // subtitle and nav h('.section-title.flex-row.flex-center', [ @@ -78,12 +86,13 @@ AccountDetailScreen.prototype.render = function() { }, 'EXPORT'), ]), - transactionList(transactions - .filter(tx => tx.txParams.from === state.address) - .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) - .sort((a, b) => b.time - a.time), state.networkVersion), - this.exportedAccount(accountDetail), - + h(ReactCSSTransitionGroup, { + transitionName: "main", + transitionEnterTimeout: 300, + transitionLeaveTimeout: 300, + }, [ + this.subview(), + ]), // transaction table /* h('section.flex-column', [ @@ -94,72 +103,41 @@ AccountDetailScreen.prototype.render = function() { ) } +AccountDetailScreen.prototype.subview = function() { + var subview + try { + subview = this.props.accountDetail.subview + } catch (e) { + subview = null + } + + switch (subview) { + case 'transactions': + return this.transactionList() + case 'export': + var state = extend({key: 'export'}, this.props) + return h(ExportAccountView, state) + default: + return this.transactionList() + } +} + +AccountDetailScreen.prototype.transactionList = function() { + var state = this.props + var transactions = state.transactions + + return transactionList(transactions + .filter(tx => tx.txParams.from === state.address) + .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) + .sort((a, b) => b.time - a.time), state.networkVersion) +} + AccountDetailScreen.prototype.navigateToAccounts = function(event){ event.stopPropagation() this.props.dispatch(actions.showAccountsPage()) } -AccountDetailScreen.prototype.exportAccount = function(address) { - this.props.dispatch(actions.exportAccount(address)) -} - AccountDetailScreen.prototype.requestAccountExport = function() { this.props.dispatch(actions.requestExportAccount()) } -AccountDetailScreen.prototype.exportedAccount = function(accountDetail) { - if (!accountDetail) return - var accountExport = accountDetail.accountExport - - var notExporting = accountExport === 'none' - var exportRequested = accountExport === 'requested' - var accountExported = accountExport === 'completed' - - if (notExporting) return - - if (exportRequested) { - var warning = `Exporting your private key is very dangerous, - and you should only do it if you know what you're doing.` - var confirmation = `If you're absolutely sure, type "I understand" below and - hit Enter.` - return h('div', {}, [ - h('p.error', warning), - h('p', confirmation), - h('input#exportAccount', { - onKeyPress: this.onExportKeyPress.bind(this), - }) - ]) - } - - if (accountExported) { - return h('div.privateKey', { - - }, [ - h('label', 'Your private key (click to copy):'), - h('p.error.cursor-pointer', { - style: { - textOverflow: 'ellipsis', - overflow: 'hidden', - webkitUserSelect: 'text', - width: '100%', - }, - onClick: function(event) { - copyToClipboard(accountDetail.privateKey) - } - }, accountDetail.privateKey), - ]) - } -} - -AccountDetailScreen.prototype.onExportKeyPress = function(event) { - if (event.key !== 'Enter') return - event.preventDefault() - - var input = document.getElementById('exportAccount') - if (input.value === 'I understand') { - this.props.dispatch(actions.exportAccount(this.props.address)) - } else { - input.value = '' - input.placeholder = 'Please retype "I understand" exactly.' - } -} diff --git a/ui/app/actions.js b/ui/app/actions.js index 072139e1a..9a8ba76d1 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -108,7 +108,6 @@ function tryUnlockMetamask(password) { return (dispatch) => { dispatch(this.unlockInProgress()) _accountManager.submitPassword(password, (err, selectedAccount) => { - dispatch(this.hideLoadingIndication()) if (err) { dispatch(this.unlockFailed()) } else { diff --git a/ui/app/app.js b/ui/app/app.js index 94c72a3c8..a4ce40881 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -65,7 +65,7 @@ App.prototype.render = function() { h('.flex-column.flex-grow.full-height', { style: { // Windows was showing a vertical scroll bar: - overflowY: 'hidden', + overflow: 'hidden', } }, [ @@ -82,6 +82,7 @@ App.prototype.render = function() { h('.app-primary.flex-grow' + (transForward ? '.from-right' : '.from-left'), { style: { height: '380px', + width: '360px', } }, [ h(ReactCSSTransitionGroup, { diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js new file mode 100644 index 000000000..f79a533ba --- /dev/null +++ b/ui/app/components/account-export.js @@ -0,0 +1,87 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const actions = require('../actions') + +module.exports = ExportAccountView + + +inherits(ExportAccountView, Component) +function ExportAccountView() { + Component.call(this) +} + +ExportAccountView.prototype.render = function() { + console.log("EXPORT VIEW") + console.dir(this.props) + var state = this.props + var accountDetail = state.accountDetail + + if (!accountDetail) return h('div') + var accountExport = accountDetail.accountExport + + var notExporting = accountExport === 'none' + var exportRequested = accountExport === 'requested' + var accountExported = accountExport === 'completed' + + if (notExporting) return h('div') + + if (exportRequested) { + var warning = `Exporting your private key is very dangerous, + and you should only do it if you know what you're doing.` + var confirmation = `If you're absolutely sure, type "I understand" below and + submit.` + return h('div', { key: 'exporting' }, [ + h('p.error', warning), + h('p', confirmation), + h('input#exportAccount', { + onKeyPress: this.onExportKeyPress.bind(this), + }), + h('button', { + onClick: () => this.onExportKeyPress({ key: 'Enter', preventDefault: () => {} }), + }, 'Submit'), + h('button', { + onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)) + }, 'Cancel'), + ]) + } + + if (accountExported) { + return h('div.privateKey', { + + }, [ + h('label', 'Your private key (click to copy):'), + h('p.error.cursor-pointer', { + style: { + textOverflow: 'ellipsis', + overflow: 'hidden', + webkitUserSelect: 'text', + width: '100%', + }, + onClick: function(event) { + copyToClipboard(accountDetail.privateKey) + } + }, accountDetail.privateKey), + h('button', { + onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)) + }, 'Done'), + ]) + } +} + +ExportAccountView.prototype.onExportKeyPress = function(event) { + if (event.key !== 'Enter') return + event.preventDefault() + + var input = document.getElementById('exportAccount') + if (input.value === 'I understand') { + this.props.dispatch(actions.exportAccount(this.props.address)) + } else { + input.value = '' + input.placeholder = 'Please retype "I understand" exactly.' + } +} + +ExportAccountView.prototype.exportAccount = function(address) { + this.props.dispatch(actions.exportAccount(address)) +} diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 99a325e35..90f2955e6 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -4,7 +4,7 @@ const addressSummary = require('../util').addressSummary const explorerLink = require('../../lib/explorer-link') module.exports = function(transactions, network) { - return h('details', [ + return h('details', { key: 'transaction-list' }, [ h('summary', [ h('div.font-small', {style: {display: 'inline'}}, 'Transactions'), diff --git a/ui/app/css/transitions.css b/ui/app/css/transitions.css index 3d0bf46a1..e2225a98d 100644 --- a/ui/app/css/transitions.css +++ b/ui/app/css/transitions.css @@ -19,6 +19,7 @@ position: absolute; width: 100%; transition: transform 300ms ease-in-out; + overflow-x: hidden; } /* final positions */ diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 14f92a8c5..309351956 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -23,6 +23,9 @@ function reduceApp(state, action) { var appState = extend({ currentView: seedWords ? seedConfView : defaultView, + accountDetail: { + subview: 'transactions', + }, currentDomain: 'example.com', transForward: true, // Used to render transition direction isLoading: false, // Used to display loading indicator @@ -109,7 +112,9 @@ function reduceApp(state, action) { case actions.UNLOCK_METAMASK: return extend(appState, { currentView: {}, + detailView: {}, transForward: true, + isLoading: false, warning: null, }) @@ -131,6 +136,7 @@ function reduceApp(state, action) { return extend(appState, { currentView: {}, accountDetail: { + subview: 'transactions', accountExport: 'none', privateKey: '', }, @@ -144,6 +150,7 @@ function reduceApp(state, action) { context: action.value || account, }, accountDetail: { + subview: 'transactions', accountExport: 'none', privateKey: '', }, @@ -157,6 +164,7 @@ function reduceApp(state, action) { context: action.value, }, accountDetail: { + subview: 'transactions', accountExport: 'none', privateKey: '', }, @@ -218,6 +226,9 @@ function reduceApp(state, action) { name: 'accountDetail', context: state.metamask.selectedAddress, }, + accountDetail: { + subview: 'transactions', + }, }) } @@ -285,7 +296,13 @@ function reduceApp(state, action) { case actions.REQUEST_ACCOUNT_EXPORT: return extend(appState, { + transForward: true, + currentView: { + name: 'accountDetail', + context: appState.currentView.context, + }, accountDetail: { + subview: 'export', accountExport: 'requested', }, }) @@ -293,6 +310,7 @@ function reduceApp(state, action) { case actions.EXPORT_ACCOUNT: return extend(appState, { accountDetail: { + subview: 'export', accountExport: 'completed', }, }) @@ -300,6 +318,7 @@ function reduceApp(state, action) { case actions.SHOW_PRIVATE_KEY: return extend(appState, { accountDetail: { + subview: 'export', accountExport: 'completed', privateKey: action.value, }, |