├── .babelrc ├── .editorconfig ├── .electron-vue ├── build.js ├── dev-client.js ├── dev-runner.js ├── webpack.main.config.js ├── webpack.renderer.config.js └── webpack.web.config.js ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── appveyor.yml ├── bin └── translations.js ├── build └── icons │ ├── 256x256.png │ ├── icon.icns │ └── icon.ico ├── cmc.png ├── dist ├── electron │ └── .gitkeep └── web │ └── .gitkeep ├── index.js ├── package-lock.json ├── package.json ├── src ├── index.ejs ├── main │ ├── index.dev.js │ ├── index.js │ ├── menu │ │ └── index.js │ └── services │ │ ├── db.js │ │ ├── index.js │ │ └── storage.js └── renderer │ ├── App.vue │ ├── assets │ ├── .gitkeep │ ├── fonts │ │ ├── FreeMono.ttf │ │ ├── Gilroy-Medium.otf │ │ ├── Gilroy-Regular.otf │ │ ├── Gilroy-SemiBold.otf │ │ ├── Proxima Nova Black It.otf │ │ ├── Proxima Nova Black.otf │ │ ├── Proxima Nova Bold It.otf │ │ ├── Proxima Nova Bold.otf │ │ ├── Proxima Nova Light It.otf │ │ ├── Proxima Nova Light.otf │ │ ├── Proxima Nova Reg It.otf │ │ ├── Proxima Nova Reg.otf │ │ ├── Proxima Nova Sbold It.otf │ │ ├── Proxima Nova Sbold.otf │ │ ├── Proxima Nova Thin It.otf │ │ ├── Proxima Nova Thin.otf │ │ ├── Proxima Nova Xbold It.otf │ │ └── Proxima Nova Xbold.otf │ ├── img │ │ ├── Kucoin_icon.svg │ │ ├── circle-1.svg │ │ ├── circle-2.svg │ │ ├── circle-3.svg │ │ ├── cmc.svg │ │ └── token-icons │ │ │ ├── APH.png │ │ │ ├── BTC.png │ │ │ ├── ETH.png │ │ │ ├── GAS.png │ │ │ └── NEO.png │ ├── scss │ │ ├── _base.scss │ │ ├── _buttons.scss │ │ ├── _fonts.scss │ │ ├── _functions.scss │ │ ├── _globals.scss │ │ ├── _mixins.scss │ │ ├── _night.scss │ │ ├── _print.scss │ │ ├── _tables.scss │ │ ├── _tiles.scss │ │ ├── _type.scss │ │ └── _variables.scss │ └── video │ │ └── login.mp4 │ ├── components │ ├── Assets.vue │ ├── AuthenticatedWrapper.vue │ ├── BuyAph.vue │ ├── Commit.vue │ ├── CopyText.vue │ ├── Dashboard.vue │ ├── DatePicker.vue │ ├── Dex.vue │ ├── DexInput.vue │ ├── Form.vue │ ├── History.vue │ ├── Holding.vue │ ├── Icon.vue │ ├── Input.vue │ ├── Login.vue │ ├── PortfolioHeader.vue │ ├── Radio.vue │ ├── RequestErrorMessage.vue │ ├── Select.vue │ ├── Settings.vue │ ├── Sidebar.vue │ ├── SimpleTransactions.vue │ ├── SpinnerWrapper.vue │ ├── TimestampFromNow.vue │ ├── TokenIcon.vue │ ├── TokenSale.vue │ ├── TransactionsSidebar.vue │ ├── Zoom.vue │ ├── assets │ │ └── AssetTable.vue │ ├── charts │ │ ├── LineChart.vue │ │ └── SimpleDonut.vue │ ├── dashboard │ │ ├── ClaimGasButton.vue │ │ ├── Contacts.vue │ │ ├── Graph.vue │ │ ├── Holding.vue │ │ ├── Holdings.vue │ │ ├── RecentTransactions.vue │ │ ├── Send.vue │ │ ├── Summary.vue │ │ ├── TokenStats.vue │ │ ├── TopRightTile.vue │ │ └── TransactionDetail.vue │ ├── dex │ │ ├── Chart.vue │ │ ├── MarketMegaSelector.vue │ │ ├── MarketSelection.vue │ │ ├── OrderBook.vue │ │ ├── OrderForm.vue │ │ ├── OrderHistory.vue │ │ └── TradeHistory.vue │ ├── history │ │ ├── Search.vue │ │ └── Table.vue │ ├── login │ │ ├── CreateWallet.vue │ │ ├── EncryptedKey.vue │ │ ├── Landing.vue │ │ ├── Ledger.vue │ │ ├── LoginFormWrapper.vue │ │ ├── Logo.vue │ │ ├── Menu.vue │ │ ├── PrivateKey.vue │ │ ├── PrivateKeySeedWords.vue │ │ ├── SavedWallet.vue │ │ └── WalletCreated.vue │ ├── modals │ │ ├── AddEditContactModal.vue │ │ ├── AddTokenModal.vue │ │ ├── AddressModal.vue │ │ ├── ClaimGasModal.vue │ │ ├── ClaimModal.vue │ │ ├── CommitInfo.vue │ │ ├── CommitModal.vue │ │ ├── ConfirmDismissKycModal.vue │ │ ├── DepositWithdrawModal.vue │ │ ├── DexDemoConfirmation.vue │ │ ├── DexOutOfDate.vue │ │ ├── FractureGasModal.vue │ │ ├── ImportAWalletModal.vue │ │ ├── KycModal.vue │ │ ├── LoginToWalletModal.vue │ │ ├── ModalWrapper.vue │ │ ├── OrderConfirmationModal.vue │ │ ├── SendWithLedgerModal.vue │ │ ├── WalletBackupModal.vue │ │ ├── WalletBackupModalBTC.vue │ │ └── WithdrawInProgressModal.vue │ └── settings │ │ ├── AddressBook.vue │ │ ├── Preferences.vue │ │ ├── WalletActions.vue │ │ └── Wallets.vue │ ├── constants.js │ ├── decorators │ ├── constants.js │ ├── index.js │ └── services.js │ ├── error-handler.js │ ├── l10n │ ├── cn.json │ ├── de.json │ ├── en.json │ ├── jp.json │ ├── ko.json │ ├── nl.json │ └── ru.json │ ├── libraries.js │ ├── main.js │ ├── mixins │ ├── alerts.js │ ├── auth.js │ ├── formatting.js │ ├── index.js │ ├── online.js │ └── requests.js │ ├── router │ └── index.js │ ├── services │ ├── alerts.js │ ├── assets.js │ ├── bwclient.js │ ├── contacts.js │ ├── db.js │ ├── dex.js │ ├── ethclient.js │ ├── formatting.js │ ├── index.js │ ├── ledger.js │ ├── neo.js │ ├── network.js │ ├── settings.js │ ├── storage.js │ ├── storageNew.js │ ├── valuation.js │ └── wallets.js │ ├── shared-components │ └── index.js │ └── store │ ├── actions.js │ ├── getters.js │ ├── index.js │ └── mutations.js ├── static ├── .gitkeep └── charting_library │ ├── charting_library.min.d.ts │ ├── charting_library.min.js │ ├── datafeed-api.d.ts │ └── static │ ├── bundles │ ├── 13.280894673316ad6ac6f2.js │ ├── crosshair.6c091f7d5427d0c5e6d9dc3a90eb2b20.cur │ ├── dot.ed68e83c16f77203e73dbc4c3a7c7fa1.cur │ ├── ds-property-pages.1a3d233b8aa4552a7048.js │ ├── editobjectdialog.25fa62e6b4f8125e697e.js │ ├── eraser.0579d40b812fa2c3ffe72e5803a6e14c.cur │ ├── go-to-date-dialog-impl.1e876e63af6d26496269.js │ ├── grab.bc156522a6b55a60be9fae15c14b66c5.cur │ ├── grabbing.1c0862a8a8c0fb02885557bc97fdafe7.cur │ ├── ie-fallback-logos.b27f679ee44b7d0992e1.js │ ├── lazy-jquery-ui.8a95a81e0b032b2d76df.js │ ├── lazy-velocity.97588d47c84409f2bc4b.js │ ├── library.77596ca6783cb5996d22.js │ ├── library.a8de6f8cf4dda6895071c6ec45f900d9.css │ ├── lt-pane-views.96fd54d9b7bad567d490.js │ ├── objecttreedialog.3f22589e98a1cedf9028.js │ ├── propertypagesfactory.54b21a18753b2d8c83c2.js │ ├── symbol-info-dialog-impl.f6bc55c14cd39967110a.js │ ├── take-chart-image-dialog-impl.d8f49fce300496653730.js │ ├── vendors.a94ef44ed5c201cefcf6ad7460788c1a.css │ ├── vendors.be39e0d831d7b65e9f31.js │ └── zoom.e21f24dd632c7069139bc47ae89c54b5.cur │ ├── fonts │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff │ ├── images │ ├── balloon.png │ ├── bar-loader.gif │ ├── button-bg.png │ ├── charting_library │ │ ├── logo-widget-copyright-faded.png │ │ └── logo-widget-copyright.png │ ├── controlll.png │ ├── delayed.png │ ├── dialogs │ │ ├── checkbox.png │ │ ├── close-flat.png │ │ ├── large-slider-handle.png │ │ ├── linewidth-slider.png │ │ └── opacity-slider.png │ ├── icons.png │ ├── prediction-clock-black.png │ ├── prediction-clock-white.png │ ├── prediction-failure-white.png │ ├── prediction-success-white.png │ ├── select-bg.png │ ├── sidetoolbar │ │ ├── instruments.png │ │ └── toolgroup.png │ ├── svg │ │ ├── chart │ │ │ ├── bucket2.svg │ │ │ ├── font.svg │ │ │ ├── large-slider-handle.svg │ │ │ └── pencil2.svg │ │ └── question-mark-rounded.svg │ ├── tvcolorpicker-bg-gradient.png │ ├── tvcolorpicker-bg.png │ ├── tvcolorpicker-check.png │ ├── tvcolorpicker-sprite.png │ └── warning-icon.png │ ├── js │ └── external │ │ └── spin.min.js │ ├── localization │ └── translations │ │ ├── ar.json │ │ ├── cs.json │ │ ├── da_DK.json │ │ ├── de.json │ │ ├── el.json │ │ ├── en.json │ │ ├── es.json │ │ ├── et_EE.json │ │ ├── fa.json │ │ ├── fr.json │ │ ├── he_IL.json │ │ ├── hu_HU.json │ │ ├── id_ID.json │ │ ├── it.json │ │ ├── ja.json │ │ ├── ko.json │ │ ├── ms_MY.json │ │ ├── nl_NL.json │ │ ├── no.json │ │ ├── pl.json │ │ ├── pt.json │ │ ├── ro.json │ │ ├── ru.json │ │ ├── sk_SK.json │ │ ├── sv.json │ │ ├── th.json │ │ ├── tr.json │ │ ├── vi.json │ │ ├── widgets-copyrights.json │ │ ├── widgets-copyrights.json.example │ │ ├── zh.json │ │ └── zh_TW.json │ ├── styles.css │ └── tv-chart.7580da73a91e1354cb09.html └── test ├── .eslintrc ├── e2e ├── index.js ├── specs │ └── Launch.spec.js └── utils.js └── unit ├── index.js ├── karma.conf.js └── specs └── renderer ├── components ├── Holding.spec.js ├── PortfolioHeader.spec.js ├── TransactionsSidebar.spec.js ├── charts │ └── SimpleDonut.spec.js ├── login │ ├── CreateWallet.spec.js │ ├── EncryptedKey.spec.js │ ├── Landing.spec.js │ └── SavedWallet.spec.js └── utils.js └── services ├── alerts.spec.js └── formatting.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "comments": false, 3 | "env": { 4 | "test": { 5 | "presets": [ 6 | ["env", { 7 | "targets": { "node": 7 } 8 | }], 9 | "stage-0" 10 | ], 11 | "plugins": ["istanbul"] 12 | }, 13 | "main": { 14 | "presets": [ 15 | ["env", { 16 | "targets": { "node": 7 } 17 | }], 18 | "stage-0" 19 | ] 20 | }, 21 | "renderer": { 22 | "presets": [ 23 | ["env", { 24 | "modules": false 25 | }], 26 | "stage-0" 27 | ] 28 | }, 29 | "web": { 30 | "presets": [ 31 | ["env", { 32 | "modules": false 33 | }], 34 | "stage-0" 35 | ] 36 | } 37 | }, 38 | "plugins": ["transform-runtime"] 39 | } 40 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /.electron-vue/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | const { say } = require('cfonts') 6 | const chalk = require('chalk') 7 | const del = require('del') 8 | const { spawn } = require('child_process') 9 | const webpack = require('webpack') 10 | const Multispinner = require('multispinner') 11 | 12 | 13 | const mainConfig = require('./webpack.main.config') 14 | const rendererConfig = require('./webpack.renderer.config') 15 | const webConfig = require('./webpack.web.config') 16 | 17 | const doneLog = chalk.bgGreen.white(' DONE ') + ' ' 18 | const errorLog = chalk.bgRed.white(' ERROR ') + ' ' 19 | const okayLog = chalk.bgBlue.white(' OKAY ') + ' ' 20 | const isCI = process.env.CI || false 21 | 22 | if (process.env.BUILD_TARGET === 'clean') clean() 23 | else if (process.env.BUILD_TARGET === 'web') web() 24 | else build() 25 | 26 | function clean () { 27 | del.sync(['build/*', '!build/icons', '!build/icons/icon.*']) 28 | console.log(`\n${doneLog}\n`) 29 | process.exit() 30 | } 31 | 32 | function build () { 33 | greeting() 34 | 35 | del.sync(['dist/electron/*', '!.gitkeep']) 36 | 37 | const tasks = ['main', 'renderer'] 38 | const m = new Multispinner(tasks, { 39 | preText: 'building', 40 | postText: 'process' 41 | }) 42 | 43 | let results = '' 44 | 45 | m.on('success', () => { 46 | process.stdout.write('\x1B[2J\x1B[0f') 47 | console.log(`\n\n${results}`) 48 | console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`) 49 | process.exit() 50 | }) 51 | 52 | pack(mainConfig).then(result => { 53 | results += result + '\n\n' 54 | m.success('main') 55 | }).catch(err => { 56 | m.error('main') 57 | console.log(`\n ${errorLog}failed to build main process`) 58 | console.error(`\n${err}\n`) 59 | process.exit(1) 60 | }) 61 | 62 | pack(rendererConfig).then(result => { 63 | results += result + '\n\n' 64 | m.success('renderer') 65 | }).catch(err => { 66 | m.error('renderer') 67 | console.log(`\n ${errorLog}failed to build renderer process`) 68 | console.error(`\n${err}\n`) 69 | process.exit(1) 70 | }) 71 | } 72 | 73 | function pack (config) { 74 | return new Promise((resolve, reject) => { 75 | webpack(config, (err, stats) => { 76 | if (err) reject(err.stack || err) 77 | else if (stats.hasErrors()) { 78 | let err = '' 79 | 80 | stats.toString({ 81 | chunks: false, 82 | colors: true 83 | }) 84 | .split(/\r?\n/) 85 | .forEach(line => { 86 | err += ` ${line}\n` 87 | }) 88 | 89 | reject(err) 90 | } else { 91 | resolve(stats.toString({ 92 | chunks: false, 93 | colors: true 94 | })) 95 | } 96 | }) 97 | }) 98 | } 99 | 100 | function web () { 101 | del.sync(['dist/web/*', '!.gitkeep']) 102 | webpack(webConfig, (err, stats) => { 103 | if (err || stats.hasErrors()) console.log(err) 104 | 105 | console.log(stats.toString({ 106 | chunks: false, 107 | colors: true 108 | })) 109 | 110 | process.exit() 111 | }) 112 | } 113 | 114 | function greeting () { 115 | const cols = process.stdout.columns 116 | let text = '' 117 | 118 | if (cols > 85) text = 'lets-build' 119 | else if (cols > 60) text = 'lets-|build' 120 | else text = false 121 | 122 | if (text && !isCI) { 123 | say(text, { 124 | colors: ['yellow'], 125 | font: 'simple3d', 126 | space: false 127 | }) 128 | } else console.log(chalk.yellow.bold('\n lets-build')) 129 | console.log() 130 | } 131 | -------------------------------------------------------------------------------- /.electron-vue/dev-client.js: -------------------------------------------------------------------------------- 1 | const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 2 | 3 | hotClient.subscribe(event => { 4 | /** 5 | * Reload browser when HTMLWebpackPlugin emits a new index.html 6 | * 7 | * Currently disabled until jantimon/html-webpack-plugin#680 is resolved. 8 | * https://github.com/SimulatedGREG/electron-vue/issues/437 9 | * https://github.com/jantimon/html-webpack-plugin/issues/680 10 | */ 11 | // if (event.action === 'reload') { 12 | // window.location.reload() 13 | // } 14 | 15 | /** 16 | * Notify `mainWindow` when `main` process is compiling, 17 | * giving notice for an expected reload of the `electron` process 18 | */ 19 | if (event.action === 'compiling') { 20 | document.body.innerHTML += ` 21 | 34 | 35 |
36 | Compiling Main Process... 37 |
38 | ` 39 | } 40 | }) 41 | -------------------------------------------------------------------------------- /.electron-vue/webpack.main.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'main' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 10 | 11 | let mainConfig = { 12 | entry: { 13 | main: path.join(__dirname, '../src/main/index.js') 14 | }, 15 | externals: [ 16 | ...Object.keys(dependencies || {}) 17 | ], 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.(js)$/, 22 | enforce: 'pre', 23 | exclude: /node_modules/, 24 | use: { 25 | loader: 'eslint-loader', 26 | options: { 27 | formatter: require('eslint-friendly-formatter') 28 | } 29 | } 30 | }, 31 | { 32 | test: /\.js$/, 33 | use: 'babel-loader', 34 | exclude: /node_modules/ 35 | }, 36 | { 37 | test: /\.node$/, 38 | use: 'node-loader' 39 | } 40 | ] 41 | }, 42 | node: { 43 | __dirname: process.env.NODE_ENV !== 'production', 44 | __filename: process.env.NODE_ENV !== 'production' 45 | }, 46 | output: { 47 | filename: '[name].js', 48 | libraryTarget: 'commonjs2', 49 | path: path.join(__dirname, '../dist/electron') 50 | }, 51 | plugins: [ 52 | new webpack.NoEmitOnErrorsPlugin() 53 | ], 54 | resolve: { 55 | extensions: ['.js', '.json', '.node'] 56 | }, 57 | target: 'electron-main' 58 | } 59 | 60 | /** 61 | * Adjust mainConfig for development settings 62 | */ 63 | if (process.env.NODE_ENV !== 'production') { 64 | mainConfig.plugins.push( 65 | new webpack.DefinePlugin({ 66 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 67 | }) 68 | ) 69 | } 70 | 71 | /** 72 | * Adjust mainConfig for production settings 73 | */ 74 | if (process.env.NODE_ENV === 'production') { 75 | mainConfig.plugins.push( 76 | new BabiliWebpackPlugin(), 77 | new webpack.DefinePlugin({ 78 | 'process.env.NODE_ENV': '"production"' 79 | }) 80 | ) 81 | } 82 | 83 | module.exports = mainConfig 84 | -------------------------------------------------------------------------------- /.electron-vue/webpack.web.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'web' 4 | 5 | const path = require('path') 6 | const webpack = require('webpack') 7 | 8 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 9 | const CopyWebpackPlugin = require('copy-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const HtmlWebpackPlugin = require('html-webpack-plugin') 12 | 13 | let webConfig = { 14 | devtool: '#cheap-module-eval-source-map', 15 | entry: { 16 | web: path.join(__dirname, '../src/renderer/main.js') 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.(js|vue)$/, 22 | enforce: 'pre', 23 | exclude: /node_modules/, 24 | use: { 25 | loader: 'eslint-loader', 26 | options: { 27 | formatter: require('eslint-friendly-formatter') 28 | } 29 | } 30 | }, 31 | { 32 | test: /\.css$/, 33 | use: ExtractTextPlugin.extract({ 34 | fallback: 'style-loader', 35 | use: 'css-loader' 36 | }) 37 | }, 38 | { 39 | test: /\.html$/, 40 | use: 'vue-html-loader' 41 | }, 42 | { 43 | test: /\.js$/, 44 | use: 'babel-loader', 45 | include: [ path.resolve(__dirname, '../src/renderer') ], 46 | exclude: /node_modules/ 47 | }, 48 | { 49 | test: /\.vue$/, 50 | use: { 51 | loader: 'vue-loader', 52 | options: { 53 | extractCSS: true, 54 | loaders: { 55 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 56 | scss: 'vue-style-loader!css-loader!sass-loader' 57 | } 58 | } 59 | } 60 | }, 61 | { 62 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 63 | use: { 64 | loader: 'url-loader', 65 | query: { 66 | limit: 10000, 67 | name: 'imgs/[name].[ext]' 68 | } 69 | } 70 | }, 71 | { 72 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 73 | use: { 74 | loader: 'url-loader', 75 | query: { 76 | limit: 10000, 77 | name: 'fonts/[name].[ext]' 78 | } 79 | } 80 | } 81 | ] 82 | }, 83 | plugins: [ 84 | new ExtractTextPlugin('styles.css'), 85 | new HtmlWebpackPlugin({ 86 | filename: 'index.html', 87 | template: path.resolve(__dirname, '../src/index.ejs'), 88 | minify: { 89 | collapseWhitespace: true, 90 | removeAttributeQuotes: true, 91 | removeComments: true 92 | }, 93 | nodeModules: false 94 | }), 95 | new webpack.DefinePlugin({ 96 | 'process.env.IS_WEB': 'true' 97 | }), 98 | new webpack.HotModuleReplacementPlugin(), 99 | new webpack.NoEmitOnErrorsPlugin() 100 | ], 101 | output: { 102 | filename: '[name].js', 103 | path: path.join(__dirname, '../dist/web') 104 | }, 105 | resolve: { 106 | alias: { 107 | '@': path.join(__dirname, '../src/renderer'), 108 | 'vue$': 'vue/dist/vue.esm.js' 109 | }, 110 | extensions: ['.js', '.vue', '.json', '.css'] 111 | }, 112 | target: 'web' 113 | } 114 | 115 | /** 116 | * Adjust webConfig for production settings 117 | */ 118 | if (process.env.NODE_ENV === 'production') { 119 | webConfig.devtool = '' 120 | 121 | webConfig.plugins.push( 122 | new BabiliWebpackPlugin(), 123 | new CopyWebpackPlugin([ 124 | { 125 | from: path.join(__dirname, '../static'), 126 | to: path.join(__dirname, '../dist/web/static'), 127 | ignore: ['.*'] 128 | } 129 | ]), 130 | new webpack.DefinePlugin({ 131 | 'process.env.NODE_ENV': '"production"' 132 | }), 133 | new webpack.LoaderOptionsPlugin({ 134 | minimize: true 135 | }) 136 | ) 137 | } 138 | 139 | module.exports = webConfig 140 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/unit/coverage/** 2 | test/unit/*.js 3 | test/e2e/*.js 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | env: { 8 | browser: true, 9 | node: true 10 | }, 11 | extends: 'airbnb-base', 12 | globals: { 13 | __static: true, 14 | _: true, 15 | accounting: true, 16 | axios: true, 17 | moment: true 18 | }, 19 | plugins: [ 20 | 'html' 21 | ], 22 | 'rules': { 23 | 'global-require': 0, 24 | 'import/no-unresolved': 0, 25 | 'no-param-reassign': 0, 26 | 'no-shadow': 0, 27 | 'import/extensions': 0, 28 | 'import/newline-after-import': 0, 29 | 'no-multi-assign': 0, 30 | 'import/no-extraneous-dependencies': 0, 31 | 'import/prefer-default-export': 0, 32 | // allow debugger during development 33 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 34 | 'no-console': 0, 35 | 'no-underscore-dangle': 0, 36 | 'arrow-body-style': 0, 37 | 'array-callback-return': 0, 38 | 'max-len': [2, 120], 39 | 'id-length': [2, {min: 3, exceptions: ['e', 'vm', '_', 'el', 'i', 'to', 'tx', 'id', 'db', 'en'], properties: 'never'}], 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js text eol=lf 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Ticket 2 | * 3 | 4 | ## Changes 5 | * 6 | 7 | ## Screenshots 8 | 9 | ## Code Coverage 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .history 3 | dist/electron/* 4 | dist/web/* 5 | build/* 6 | !build/icons 7 | coverage 8 | node_modules/ 9 | npm-debug.log 10 | npm-debug.log.* 11 | thumbs.db 12 | !.gitkeep 13 | src/renderer/l10n/todo-*.json 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Commented sections below can be used to run tests on the CI server 2 | # https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing 3 | osx_image: xcode8.3 4 | sudo: required 5 | dist: trusty 6 | language: c 7 | matrix: 8 | include: 9 | - os: osx 10 | - os: linux 11 | env: CC=clang CXX=clang++ npm_config_clang=1 12 | compiler: clang 13 | cache: 14 | directories: 15 | - node_modules 16 | - "$HOME/.electron" 17 | - "$HOME/.cache" 18 | addons: 19 | apt: 20 | packages: 21 | - libgnome-keyring-dev 22 | - icnsutils 23 | #- xvfb 24 | before_install: 25 | - mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v1.2.1/git-lfs-$([ 26 | "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-1.2.1.tar.gz 27 | | tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull 28 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi 29 | install: 30 | #- export DISPLAY=':99.0' 31 | #- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 32 | - nvm install 7 33 | - curl -o- -L https://yarnpkg.com/install.sh | bash 34 | - source ~/.bashrc 35 | - npm install -g xvfb-maybe 36 | - yarn 37 | script: 38 | #- xvfb-maybe node_modules/.bin/karma start test/unit/karma.conf.js 39 | #- yarn run pack && xvfb-maybe node_modules/.bin/mocha test/e2e 40 | - yarn run build 41 | branches: 42 | only: 43 | - master 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Aphelion LTD 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aph-wallet-gui 2 | 3 | > The Aphelion desktop wallet application built with [Electron](https://electronjs.org) 4 | 5 | #### Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:9080 12 | npm run dev 13 | 14 | # build electron application for production 15 | npm run build 16 | 17 | # run unit & end-to-end tests 18 | npm test 19 | 20 | # lint all JS/Vue component files in `src/` 21 | npm run lint 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Commented sections below can be used to run tests on the CI server 2 | # https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing 3 | version: 0.1.{build} 4 | 5 | branches: 6 | only: 7 | - master 8 | 9 | image: Visual Studio 2017 10 | platform: 11 | - x64 12 | 13 | cache: 14 | - node_modules 15 | - '%APPDATA%\npm-cache' 16 | - '%USERPROFILE%\.electron' 17 | - '%USERPROFILE%\AppData\Local\Yarn\cache' 18 | 19 | init: 20 | - git config --global core.autocrlf input 21 | 22 | install: 23 | - ps: Install-Product node 8 x64 24 | - choco install yarn --ignore-dependencies 25 | - git reset --hard HEAD 26 | - yarn 27 | - node --version 28 | 29 | build_script: 30 | #- yarn test 31 | - yarn build 32 | 33 | test: off 34 | -------------------------------------------------------------------------------- /bin/translations.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const _ = require('lodash'); 4 | const fs = require('fs'); 5 | const langs = [ 6 | 'de', 7 | 'cn', 8 | 'jp', 9 | 'ko', 10 | 'nl', 11 | 'ru', 12 | ]; 13 | const argv = require('minimist')(process.argv.slice(2)); 14 | const enData = require('../src/renderer/l10n/en'); 15 | const enKeys = Object.keys(enData).sort(); 16 | 17 | if (argv.todo) { 18 | todo(); 19 | } else if (argv.merge) { 20 | merge(); 21 | } else if (argv.sort) { 22 | sort(); 23 | } else { 24 | console.log('Please run with either --todo or --merge'); 25 | process.exit(1); 26 | } 27 | 28 | function sort(){ 29 | langs.unshift('en'); 30 | langs.map(lang => { 31 | console.log(`---------------\nSorting language file: ${lang}`); 32 | const path = require('path'); 33 | const filePath = path.resolve('.', 'src', 'renderer', 'l10n', lang) 34 | const data = require(filePath); 35 | const keys = Object.keys(data).sort(); 36 | const sortedData = {}; 37 | 38 | keys.map(key => { 39 | sortedData[key] = data[key]; 40 | }); 41 | 42 | const newFilePath = path.resolve('.', 'src', 'renderer', 'l10n', `${lang}.json`); 43 | fs.writeFileSync(newFilePath, JSON.stringify(sortedData, null, 2), { encoding: 'utf8' }); 44 | }); 45 | } 46 | 47 | function todo(){ 48 | langs.map(lang => { 49 | console.log(`---------------\nComparing language: ${lang}`); 50 | const path = require('path'); 51 | const filePath = path.resolve('.', 'src', 'renderer', 'l10n', lang) 52 | const data = require(filePath); 53 | const keys = Object.keys(data).sort(); 54 | const newKeys = _.differenceWith(enKeys, keys, _.isEqual); 55 | const newData = {}; 56 | 57 | console.log(`${newKeys.length} new keys found.`); 58 | 59 | newKeys.map(key => { 60 | newData[key] = enData[key]; 61 | }); 62 | 63 | // console.log(JSON.stringify(newData, null, 2)); 64 | 65 | const newFilePath = path.resolve('.', 'src', 'renderer', 'l10n', `todo-${lang}.json`); 66 | fs.writeFileSync(newFilePath, JSON.stringify(newData, null, 2), { encoding: 'utf8' }); 67 | }); 68 | } 69 | 70 | function merge(){ 71 | langs.map(lang => { 72 | console.log(`---------------\nMerging language: ${lang}`); 73 | const path = require('path'); 74 | const filePath = path.resolve('.', 'src', 'renderer', 'l10n', lang) 75 | const fileTodoPath = path.resolve('.', 'src', 'renderer', 'l10n', `todo-${lang}.json`); 76 | const data = require(filePath); 77 | const todoData = require(fileTodoPath); 78 | const todoKeys = Object.keys(todoData).sort(); 79 | const newData = {}; 80 | 81 | todoKeys.map(key => { 82 | data[key] = todoData[key]; 83 | }); 84 | 85 | const sortedAllKeys = Object.keys(data).sort(); 86 | 87 | sortedAllKeys.map(key => { 88 | newData[key] = data[key]; 89 | }); 90 | 91 | const newFilePath = path.resolve('.', 'src', 'renderer', 'l10n', `${lang}.json`); 92 | fs.writeFileSync(newFilePath, JSON.stringify(newData, null, 2), { encoding: 'utf8' }); 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /build/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/build/icons/256x256.png -------------------------------------------------------------------------------- /build/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/build/icons/icon.icns -------------------------------------------------------------------------------- /build/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/build/icons/icon.ico -------------------------------------------------------------------------------- /cmc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/cmc.png -------------------------------------------------------------------------------- /dist/electron/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/dist/electron/.gitkeep -------------------------------------------------------------------------------- /dist/web/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/dist/web/.gitkeep -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // @create-index 2 | 3 | -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Aphelion Desktop Wallet 6 | <% if (htmlWebpackPlugin.options.nodeModules) { %> 7 | 8 | 11 | <% } %> 12 | 13 | 14 |
15 | 16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/index.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used specifically and only for development. It installs 3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to 4 | * modify this file, but it can be used to extend your development 5 | * environment. 6 | */ 7 | 8 | /* eslint-disable */ 9 | 10 | // Set environment for development 11 | process.env.NODE_ENV = 'development' 12 | 13 | // Install `electron-debug` with `devtron` 14 | require('electron-debug')({ showDevTools: true }) 15 | 16 | // Install `vue-devtools` 17 | require('electron').app.on('ready', () => { 18 | let installExtension = require('electron-devtools-installer') 19 | installExtension.default(installExtension.VUEJS_DEVTOOLS) 20 | .then(() => {}) 21 | .catch(err => { 22 | console.log('Unable to install `vue-devtools`: \n', err) 23 | }) 24 | }) 25 | 26 | // Require `main` process to boot app 27 | require('./index') 28 | -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | import { app, Menu, BrowserWindow } from 'electron'; 2 | import path from 'path'; 3 | 4 | import './services'; 5 | import menuTemplate from './menu'; 6 | 7 | /** 8 | * Set `__static` path to static files in production 9 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html 10 | */ 11 | if (process.env.NODE_ENV !== 'development') { 12 | global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') // eslint-disable-line 13 | } 14 | 15 | let mainWindow; 16 | const winURL = process.env.NODE_ENV === 'development' 17 | ? 'http://localhost:9080' 18 | : `file://${__dirname}/index.html`; 19 | 20 | function createWindow() { 21 | /** 22 | * Initial window options 23 | */ 24 | mainWindow = new BrowserWindow({ 25 | height: 900, 26 | icon: path.join(__dirname, 'assets/img/icons/icon.png'), 27 | minHeight: 768, 28 | minWidth: 1366, 29 | title: 'Aphelion Desktop Wallet', 30 | titleBarStyle: 'hidden', 31 | useContentSize: true, 32 | width: 1375, 33 | }); 34 | 35 | mainWindow.loadURL(winURL); 36 | // mainWindow.webContents.openDevTools(); 37 | 38 | mainWindow.on('closed', () => { 39 | mainWindow = null; 40 | }); 41 | 42 | mainWindow.setMenu(null); 43 | Menu.setApplicationMenu(Menu.buildFromTemplate(menuTemplate(app))); 44 | } 45 | 46 | app.on('ready', createWindow); 47 | 48 | app.on('window-all-closed', () => { 49 | if (process.platform !== 'darwin') { 50 | app.quit(); 51 | } 52 | }); 53 | 54 | app.on('activate', () => { 55 | if (mainWindow === null) { 56 | createWindow(); 57 | } 58 | }); 59 | 60 | /** 61 | * Auto Updater 62 | * 63 | * Uncomment the following code below and install `electron-updater` to 64 | * support auto updating. Code Signing with a valid certificate is required. 65 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating 66 | */ 67 | 68 | /* 69 | import { autoUpdater } from 'electron-updater' 70 | 71 | autoUpdater.on('update-downloaded', () => { 72 | autoUpdater.quitAndInstall() 73 | }) 74 | 75 | app.on('ready', () => { 76 | if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates() 77 | }) 78 | */ 79 | -------------------------------------------------------------------------------- /src/main/menu/index.js: -------------------------------------------------------------------------------- 1 | export default (app) => { 2 | return [{ 3 | label: 'Application', 4 | submenu: [ 5 | { 6 | label: 'Quit', 7 | accelerator: 'Command+Q', 8 | click() { 9 | app.quit(); 10 | }, 11 | }, 12 | ], 13 | }, { 14 | label: 'Edit', 15 | submenu: [ 16 | { 17 | label: 'Cut', 18 | accelerator: 'CmdOrCtrl+X', 19 | selector: 'cut:', 20 | role: 'cut', 21 | }, 22 | { 23 | label: 'Copy', 24 | accelerator: 'CmdOrCtrl+C', 25 | selector: 'copy:', 26 | role: 'copy', 27 | }, 28 | { 29 | label: 'Paste', 30 | accelerator: 'CmdOrCtrl+V', 31 | selector: 'paste:', 32 | role: 'paste', 33 | }, 34 | { 35 | label: 'Select All', 36 | accelerator: 'CmdOrCtrl+A', 37 | selector: 'selectAll:', 38 | role: 'selectall', 39 | }, 40 | ], 41 | }, 42 | { 43 | label: 'View', 44 | submenu: [ 45 | { 46 | role: 'zoomin', 47 | }, 48 | { 49 | role: 'zoomout', 50 | }, 51 | { 52 | label: 'Reset Zoom', 53 | role: 'resetzoom', 54 | }, 55 | ], 56 | }]; 57 | }; 58 | -------------------------------------------------------------------------------- /src/main/services/db.js: -------------------------------------------------------------------------------- 1 | import PouchDB from 'pouchdb'; 2 | import PouchDBUpsert from 'pouchdb-upsert'; 3 | import ipcPromise from 'ipc-promise'; 4 | import path from 'path'; 5 | import { app } from 'electron'; 6 | 7 | import { database } from '../../renderer/constants'; 8 | 9 | // PouchDB config 10 | if (process.env.NODE_ENV === 'development') { 11 | PouchDB.debug.enable('*'); 12 | } 13 | 14 | // PouchDB plugins 15 | PouchDB.plugin(PouchDBUpsert); 16 | 17 | // Create database 18 | const db = new PouchDB(path.join(app.getPath('userData'), database.NAME), { 19 | adapter: 'leveldb', 20 | auto_compaction: true, 21 | revs_limit: 1, 22 | }); 23 | 24 | if (process.env.NODE_ENV === 'development') { 25 | db.info((err, info) => { 26 | console.log(err || info); 27 | }); 28 | } 29 | 30 | const service = { 31 | get(id) { 32 | return db.get(id); 33 | }, 34 | 35 | remove(id) { 36 | return db.remove(id); 37 | }, 38 | 39 | upsert(id, data) { 40 | return new Promise((resolve, reject) => { 41 | db 42 | .upsert(id, () => { 43 | return { data }; 44 | }) 45 | .then((response) => { 46 | resolve(response); 47 | }) 48 | .catch((error) => { 49 | reject(error); 50 | }); 51 | }); 52 | }, 53 | }; 54 | 55 | ipcPromise.on('db.get', id => service.get(id)); 56 | ipcPromise.on('db.remove', id => service.remove(id)); 57 | ipcPromise.on('db.upsert', ({ id, data }) => service.upsert(id, data)); 58 | 59 | export default service; 60 | -------------------------------------------------------------------------------- /src/main/services/index.js: -------------------------------------------------------------------------------- 1 | import db from './db'; 2 | import storage from './storage'; 3 | 4 | export { 5 | db, 6 | storage, 7 | }; 8 | -------------------------------------------------------------------------------- /src/main/services/storage.js: -------------------------------------------------------------------------------- 1 | import Store from 'electron-store'; 2 | import _ from 'lodash'; 3 | import { ipcMain } from 'electron'; 4 | 5 | const store = new Store(); 6 | const keysToRemove = [ 7 | 'aph', 8 | 'holdings', 9 | 'portfolios', 10 | 'token', 11 | 'txs', 12 | 'network.rpcClient', 13 | ]; 14 | 15 | ipcMain.on('storage.clean', (event) => { 16 | console.log(`Cleaning deprecated storage keys: ${keysToRemove.join()}`); 17 | 18 | event.returnValue = store.store = _.omit(store.store, keysToRemove); 19 | }); 20 | 21 | 22 | ipcMain.on('storage.delete', (event, key) => { 23 | store.delete(key); 24 | }); 25 | 26 | ipcMain.on('storage.set', (event, key, value) => { 27 | store.set(key, value); 28 | }); 29 | -------------------------------------------------------------------------------- /src/renderer/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/.gitkeep -------------------------------------------------------------------------------- /src/renderer/assets/fonts/FreeMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/FreeMono.ttf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Gilroy-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Gilroy-Medium.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Gilroy-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Gilroy-Regular.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Gilroy-SemiBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Gilroy-SemiBold.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Black It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Black It.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Black.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Black.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Bold It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Bold It.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Bold.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Light It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Light It.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Light.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Reg It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Reg It.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Reg.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Reg.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Sbold It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Sbold It.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Sbold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Sbold.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Thin It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Thin It.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Thin.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Thin.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Xbold It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Xbold It.otf -------------------------------------------------------------------------------- /src/renderer/assets/fonts/Proxima Nova Xbold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/fonts/Proxima Nova Xbold.otf -------------------------------------------------------------------------------- /src/renderer/assets/img/Kucoin_icon.svg: -------------------------------------------------------------------------------- 1 | Kucoin_icon 2 | -------------------------------------------------------------------------------- /src/renderer/assets/img/circle-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | circle-1 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/renderer/assets/img/circle-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/renderer/assets/img/circle-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/renderer/assets/img/cmc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/renderer/assets/img/token-icons/APH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/img/token-icons/APH.png -------------------------------------------------------------------------------- /src/renderer/assets/img/token-icons/BTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/img/token-icons/BTC.png -------------------------------------------------------------------------------- /src/renderer/assets/img/token-icons/ETH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/img/token-icons/ETH.png -------------------------------------------------------------------------------- /src/renderer/assets/img/token-icons/GAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/img/token-icons/GAS.png -------------------------------------------------------------------------------- /src/renderer/assets/img/token-icons/NEO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/img/token-icons/NEO.png -------------------------------------------------------------------------------- /src/renderer/assets/scss/_base.scss: -------------------------------------------------------------------------------- 1 | 2 | @import "~normalize.css/normalize"; 3 | 4 | ::-webkit-scrollbar { 5 | width: $border-width; 6 | } 7 | 8 | ::-webkit-scrollbar-thumb:vertical { 9 | background: $purple; 10 | } 11 | 12 | html, body { 13 | color: $dark; 14 | font-family: Proxima; 15 | font-size: $font-size; 16 | height: 100%; 17 | line-height: normal; 18 | background: white; 19 | 20 | @include lowRes() { 21 | font-size: $font-size-low-res; 22 | } 23 | } 24 | 25 | * { 26 | box-sizing: border-box; 27 | letter-spacing: $letter-spacing; 28 | } 29 | 30 | a { 31 | color: $purple; 32 | text-decoration: none; 33 | 34 | &:hover { 35 | color: $purple-hover; 36 | } 37 | 38 | &:focus { 39 | outline: none; 40 | } 41 | } 42 | 43 | .vue-flash-container { 44 | bottom: $space; 45 | position: absolute; 46 | right: $space; 47 | width: toRem(500px); 48 | z-index: 10000; 49 | } 50 | 51 | .flash__message { 52 | background: rgba($dark, .9) !important; 53 | border-radius: $border-radius; 54 | border: none; 55 | line-height: $copy-line-height; 56 | margin: 0; 57 | padding: $space-lg; 58 | word-wrap: break-word; 59 | 60 | 61 | .flash__close-button { 62 | display: none; 63 | } 64 | 65 | &.error { 66 | color: $red; 67 | } 68 | 69 | &.info { 70 | color: $purple; 71 | } 72 | 73 | &.success { 74 | color: $green; 75 | } 76 | 77 | &.warning { 78 | color: $orange; 79 | } 80 | 81 | & + .flash__message { 82 | margin-top: $space; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_buttons.scss: -------------------------------------------------------------------------------- 1 | $btn-circle-size: toRem(65px); 2 | 3 | button, input, optgroup, select, textarea { 4 | line-height: normal; 5 | } 6 | 7 | %btn-circle { 8 | @include transition(background-color, border, box-shadow, color); 9 | 10 | align-items: center; 11 | background-color: $purple; 12 | border-radius: 100%; 13 | color: white; 14 | cursor: pointer; 15 | display: inline-flex; 16 | height: $btn-circle-size; 17 | justify-content: center; 18 | width: $btn-circle-size; 19 | 20 | &:hover { 21 | background-color: $purple-hover; 22 | } 23 | 24 | .aph-icon { 25 | .icon { 26 | height: toRem(19px); 27 | } 28 | 29 | path { 30 | fill: white; 31 | } 32 | } 33 | } 34 | 35 | %btn { 36 | @include transition(background-color, border, box-shadow, color); 37 | 38 | background-color: $purple; 39 | border-radius: $border-radius; 40 | border: $border-thin; 41 | color: white; 42 | cursor: pointer; 43 | display: inline-block; 44 | font-size: toRem(14px); 45 | height: $button-height; 46 | outline: none; 47 | padding: toRem(16px) 0; 48 | text-align: center; 49 | user-select: none; 50 | vertical-align: middle; 51 | white-space: nowrap; 52 | width: 100%; 53 | 54 | &:hover { 55 | background-color: $purple-hover; 56 | } 57 | 58 | &.disabled, &:disabled { 59 | background-color: rgba($purple-hover, 0.5); 60 | color: white; 61 | cursor: not-allowed; 62 | border-color: rgba($purple-hover, 0.1); 63 | } 64 | } 65 | 66 | %btn-outline { 67 | @extend %btn; 68 | background-color: transparent; 69 | color: white; 70 | 71 | &:hover { 72 | background-color: $purple; 73 | color: white; 74 | 75 | .fill { 76 | color: white; 77 | } 78 | } 79 | 80 | &.disabled, &:disabled { 81 | background-color: transparent; 82 | border-color: white; 83 | color: white; 84 | cursor: not-allowed; 85 | } 86 | } 87 | 88 | %btn-square { 89 | @include transition(background-color, border, box-shadow, color); 90 | 91 | background-color: white; 92 | border-radius: $border-radius; 93 | border: none; 94 | color: $purple; 95 | cursor: pointer; 96 | display: flex; 97 | flex-direction: column; 98 | font-family: ProximaMedium; 99 | height: toRem(175px); 100 | outline: none; 101 | width: toRem(175px); 102 | 103 | .aph-icon { 104 | align-items: center; 105 | display: flex; 106 | flex: 1; 107 | justify-content: center; 108 | 109 | svg { 110 | height: toRem(52px); 111 | 112 | &.create { 113 | height: toRem(50px); 114 | } 115 | } 116 | 117 | .fill { 118 | fill: $dark; 119 | } 120 | } 121 | 122 | p { 123 | font-size: toRem(14px); 124 | margin: $space 0; 125 | text-align: center; 126 | } 127 | 128 | &:hover { 129 | background-color: $purple; 130 | color: white; 131 | 132 | .aph-icon { 133 | .fill { 134 | fill: white; 135 | } 136 | } 137 | } 138 | 139 | &.disabled, &:disabled { 140 | cursor: not-allowed; 141 | opacity: 0.7; 142 | } 143 | } 144 | 145 | %btn-footer { 146 | @include transition(background-color, border, box-shadow, color); 147 | 148 | background-color: $purple; 149 | border: none; 150 | color: white; 151 | cursor: pointer; 152 | font-family: ProximaMedium; 153 | font-size: toRem(16px); 154 | height: $button-height; 155 | outline: none; 156 | padding: toRem(16px) 0; 157 | text-align: center; 158 | 159 | &:hover { 160 | background-color: $purple-hover; 161 | } 162 | 163 | &.disabled, &:disabled { 164 | background-color: $background; 165 | color: $grey; 166 | cursor: not-allowed; 167 | } 168 | } 169 | 170 | %btn-footer-light { 171 | @extend %btn-footer; 172 | 173 | background-color: $background; 174 | color: $dark; 175 | 176 | &:hover { 177 | background-color: $background; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_fonts.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Gilroy'; 3 | src: url('~@/assets/fonts/Gilroy-Regular.otf'); 4 | } 5 | 6 | @font-face { 7 | font-family: 'GilroyMedium'; 8 | src: url('~@/assets/fonts/Gilroy-Medium.otf'); 9 | } 10 | 11 | @font-face { 12 | font-family: 'GilroySemibold'; 13 | src: url('~@/assets/fonts/Gilroy-SemiBold.otf'); 14 | } 15 | 16 | @font-face { 17 | font-family: 'FreeMono'; 18 | src: url('~@/assets/fonts/FreeMono.ttf'); 19 | } 20 | 21 | @font-face { 22 | font-family: 'Proxima'; 23 | src: url('~@/assets/fonts/Proxima Nova Reg.otf'); 24 | } 25 | 26 | @font-face { 27 | font-family: 'ProximaMedium'; 28 | src: url('~@/assets/fonts/Proxima Nova Sbold.otf'); 29 | } 30 | 31 | @font-face { 32 | font-family: 'ProximaSemibold'; 33 | src: url('~@/assets/fonts/Proxima Nova Sbold.otf'); 34 | } 35 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_functions.scss: -------------------------------------------------------------------------------- 1 | @function strReplace($string, $search, $replace: '') { 2 | $index: str-index($string, $search); 3 | @if $index { 4 | @return str-slice($string, 1, $index - 1) + $replace + strReplace(str-slice($string, $index + str-length($search)), $search, $replace); 5 | } 6 | 7 | @return $string; 8 | } 9 | 10 | @function toRem($size) { 11 | $remSize: $size / $font-size; 12 | 13 | @return #{$remSize}rem; 14 | } 15 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_globals.scss: -------------------------------------------------------------------------------- 1 | $font-size: 14px; 2 | $font-size-low-res: 12.5px; 3 | 4 | @import 'functions'; 5 | @import 'mixins'; 6 | @import 'variables'; 7 | 8 | @import 'buttons'; 9 | @import 'fonts'; 10 | @import 'print'; 11 | @import 'tiles'; 12 | @import 'tables'; 13 | @import 'type'; 14 | @import 'night'; 15 | @import 'node_modules/spinthatshit/src/loaders'; 16 | 17 | %light-background { 18 | background: white; 19 | border-color: white; 20 | } 21 | %disabled-text { 22 | color: $grey; 23 | } 24 | %selected-text { 25 | color: #000000; 26 | } 27 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin propertyValues($properties, $values) { 2 | @each $property in $properties { 3 | @each $value in $values { 4 | $kebabValue: strReplace($value, ' ', '-'); 5 | 6 | ".#{$property}--#{$kebabValue}" { 7 | #{$property}: #{$value}; 8 | } 9 | 10 | ".#{$property}--#{$kebabValue}--important" { 11 | #{$property}: #{$value} !important; 12 | } 13 | } 14 | } 15 | } 16 | 17 | @mixin truncate() { 18 | overflow: hidden; 19 | text-overflow: ellipsis; 20 | white-space: nowrap; 21 | } 22 | 23 | @mixin lowRes() { 24 | @media (max-width: $breakpoint), (max-height: $breakpoint-height) { 25 | @content; 26 | } 27 | } 28 | 29 | @mixin transition($props...) { 30 | $result: (); 31 | 32 | @for $i from 1 through length($props) { 33 | $prop: nth($props, $i); 34 | $result: append($result, $prop); 35 | $result: append($result, $transition); 36 | @if $i != length($props) { 37 | $result: append($result, unquote($string: ",")); 38 | } 39 | } 40 | 41 | transition: $result; 42 | } 43 | 44 | @mixin transitionFast($props...) { 45 | $result: (); 46 | 47 | @for $i from 1 through length($props) { 48 | $prop: nth($props, $i); 49 | $result: append($result, $prop); 50 | $result: append($result, $transition-fast); 51 | @if $i != length($props) { 52 | $result: append($result, unquote($string: ",")); 53 | } 54 | } 55 | 56 | transition: $result; 57 | } 58 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_night.scss: -------------------------------------------------------------------------------- 1 | #authenticated-wrapper { 2 | &.Night { 3 | #dex { 4 | color: $copy-night; 5 | background-color: $background-night-light; 6 | 7 | .aph-dex-input input, .aph-input input { 8 | color: white; 9 | } 10 | 11 | .aph-select { 12 | .aph-select--dropdown { 13 | background: $background-night-light; 14 | border-color: $select-border-night; 15 | color: $copy-night; 16 | 17 | > li { 18 | &.selected, &:hover { 19 | background-color: $purple; 20 | color: white; 21 | } 22 | } 23 | } 24 | } 25 | 26 | .aph-select.is-light { 27 | .aph-select--label { 28 | background: $background-night-light; 29 | color: white; 30 | } 31 | 32 | .fill { 33 | fill: white; 34 | } 35 | } 36 | 37 | .aph-icon { 38 | .fill { 39 | fill: white; 40 | } 41 | } 42 | 43 | .asks { 44 | .size-bar { 45 | background-color: #5b2f40 !important; 46 | 47 | &.size-total { 48 | background-color: #441e35 !important; 49 | } 50 | } 51 | } 52 | 53 | .bids { 54 | .size-bar { 55 | background-color: #3b5459 !important; 56 | 57 | &.size-total { 58 | background-color: #233c40 !important; 59 | } 60 | } 61 | } 62 | 63 | #dex--orderform .body .side .buy-btn, #dex--orderform .body .footer .order-btn.buy-btn { 64 | border-color: #3b5459; 65 | } 66 | 67 | #dex--orderform .body .side .buy-btn.selected, #dex--orderform .body .footer .order-btn.buy-btn:hover { 68 | background-color: #233c40; 69 | } 70 | 71 | #dex--orderform .body .side .sell-btn, #dex--orderform .body .footer .order-btn.sell-btn { 72 | border-color: #5b2f40; 73 | } 74 | 75 | #dex--orderform .body .side .sell-btn.selected, #dex--orderform .body .footer .order-btn.sell-btn:hover { 76 | background-color: #441e35; 77 | } 78 | 79 | .aph-modal-wrapper { 80 | background: rgba(206, 205, 509, 0.35); 81 | 82 | & > .content { 83 | background-color: #1d1c31; 84 | } 85 | } 86 | 87 | .spinner-container { 88 | background: rgba(206, 205, 509, 0.2); 89 | } 90 | 91 | %disabled-text { 92 | color: #404156; 93 | } 94 | 95 | %selected-text { 96 | color: white; 97 | } 98 | 99 | %light-background { 100 | background: $background-night; 101 | border-color: $background-night; 102 | } 103 | 104 | %tile-light { 105 | background: $background-night; 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_print.scss: -------------------------------------------------------------------------------- 1 | @media print { 2 | #login { 3 | .left { 4 | display: none; 5 | } 6 | 7 | .right-content.login-wallet-created { 8 | background: white; 9 | } 10 | } 11 | 12 | .aph-copy-text { 13 | display: none; 14 | } 15 | 16 | .btn-group { 17 | display: none !important; 18 | } 19 | 20 | #sidebar, #portfolio-header { 21 | display: none; 22 | } 23 | 24 | #aph-wallet-backup-modal { 25 | .content { 26 | width: 100%; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_tables.scss: -------------------------------------------------------------------------------- 1 | %dex-table { 2 | border-spacing: 0; 3 | border-collapse: collapse; 4 | width: 100%; 5 | 6 | thead { 7 | th { 8 | @extend %small-uppercase-grey-label; 9 | 10 | border-bottom: $border-table-header; 11 | padding-bottom: $space-sm; 12 | text-align: left; 13 | white-space: nowrap; 14 | } 15 | } 16 | tbody { 17 | tr { 18 | vertical-align: middle; 19 | } 20 | 21 | td { 22 | border-bottom: $border-table-header; 23 | font-family: ProximaMedium; 24 | padding: $space-sm 0; 25 | text-align: left; 26 | 27 | &.green { 28 | color: $green; 29 | } 30 | 31 | &.red { 32 | color: $red; 33 | } 34 | } 35 | } 36 | } 37 | 38 | %dex-table-flex { 39 | display: flex; 40 | flex-direction: column; 41 | overflow: hidden; 42 | 43 | > .header { 44 | @extend %small-uppercase-grey-label; 45 | 46 | display: flex; 47 | flex-direction: row; 48 | padding: 0 0 $space-sm; 49 | flex: none; 50 | 51 | 52 | .cell { 53 | flex: 1; 54 | font-family: ProximaMedium; 55 | } 56 | } 57 | 58 | > .body { 59 | padding: 0; 60 | flex: 1; 61 | overflow: auto; 62 | 63 | .row { 64 | display: flex; 65 | flex-direction: row; 66 | flex-shrink: 0; 67 | 68 | .cell { 69 | flex: 1; 70 | font-family: ProximaMedium; 71 | font-size: toRem(12px); 72 | 73 | &.green { 74 | color: $green; 75 | } 76 | 77 | &.red { 78 | color: $red; 79 | } 80 | } 81 | 82 | & + .row { 83 | margin-top: $space-xs; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_tiles.scss: -------------------------------------------------------------------------------- 1 | %tile-light { 2 | background: white; 3 | border-radius: $border-radius; 4 | } 5 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_type.scss: -------------------------------------------------------------------------------- 1 | @function fontSize($size) { 2 | @return toRem($size); 3 | } 4 | 5 | %underlined-header { 6 | font-family: ProximaMedium; 7 | font-size: toRem(20px); 8 | font-weight: normal; 9 | margin: 0 0 $space 0; 10 | 11 | &:after { 12 | background: $purple; 13 | content: ""; 14 | display: block; 15 | height: toRem(3px); 16 | margin-top: $space-sm; 17 | width: toRem(55px); 18 | } 19 | } 20 | 21 | %underlined-header-sm { 22 | @extend %underlined-header; 23 | 24 | font-size: toRem(16px); 25 | } 26 | 27 | %small-uppercase-grey-label { 28 | color: $grey; 29 | font-family: ProximaMedium; 30 | font-size: toRem(12px); 31 | text-transform: uppercase; 32 | } 33 | 34 | %small-uppercase-grey-label-dark { 35 | color: $darker-grey; 36 | font-family: ProximaMedium; 37 | font-size: toRem(12px); 38 | text-transform: uppercase; 39 | } 40 | -------------------------------------------------------------------------------- /src/renderer/assets/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // Colors 2 | $background-night-light: #1f1d33; 3 | $background-night: #18162b; 4 | $background: #EEEEF9; 5 | $border-grey: #EEEEFA; 6 | $copy-night: #aeaeb8; 7 | $dark-grey: #60606b; 8 | $dark-purple: #171629; 9 | $dark: #1A193B; 10 | $darker-grey: #66688D; 11 | $green: #00E18A; 12 | $grey: #B5B5CA; 13 | $light-green: #DDF7EC; 14 | $light-grey: #F4F4FC; 15 | $lightest-grey: #f9f9ff; 16 | $light-red: #FFDBDF; 17 | $orange: #FF9800; 18 | $purple-hover: #8139FF; 19 | $purple: #752BF7; 20 | $red: #FF2F54; 21 | $select-border: darken($background, 5%); 22 | $select-border-night: lighten($background-night-light, 7%); 23 | $softer-dark: #424258; 24 | 25 | $border-radius: 4px; 26 | $border-width-thick: toRem(5px); 27 | $border-width-thin: toRem(2px); 28 | $border-width: toRem(3px); 29 | $border-table-header: $border-width-thin solid $border-grey; 30 | $border-thin: $border-width-thin solid $purple; 31 | $border: $border-width solid $purple; 32 | $box-shadow-lg: toRem(0px) toRem(15px) toRem(150px) toRem(40px) rgba($purple, 0.1); 33 | $box-shadow-sm: toRem(0px) toRem(10px) toRem(20px) toRem(10px) rgba($purple, 0.1); 34 | $box-shadow: toRem(0px) toRem(10px) toRem(40px) toRem(5px) rgba($purple, 0.05); 35 | $breakpoint-height: 900px; 36 | $breakpoint: 1500px; 37 | $button-height: toRem(52px); 38 | $copy-line-height: 150%; 39 | $dashboard-min-height: toRem(800px); 40 | $input-height: toRem(52px); 41 | $left-sidebar-width-collapsed: toRem(48px); 42 | $left-sidebar-width-expanded-lowres: toRem(288px); 43 | $left-sidebar-width-expanded: toRem(348px); 44 | $left-sidebar-width-lowres: toRem(240px); 45 | $left-sidebar-width: toRem(300px); 46 | $letter-spacing: toRem(1.5px); 47 | $right-column-width: toRem(400px); 48 | $right-sidebar-width: 45vw; 49 | $right-sidebar-width-lowres: toRem(240px); 50 | $right-sidebar-width-collapsed: toRem(48px); 51 | $right-sidebar-width-expanded: toRem(348px); 52 | $right-sidebar-width-expanded-lowres: toRem(288px); 53 | $space: $font-size; 54 | $space-lg: $space * 2; 55 | $space-sm: $space * .5; 56 | $space-xl: $space * 4; 57 | $space-xs: $space * .25; 58 | $space-xxl: $space * 6; 59 | $transition-fast: .1s ease-in-out; 60 | $transition: .3s ease-in-out; 61 | -------------------------------------------------------------------------------- /src/renderer/assets/video/login.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/assets/video/login.mp4 -------------------------------------------------------------------------------- /src/renderer/components/Assets.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 47 | 48 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/renderer/components/BuyAph.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 45 | 46 | 138 | -------------------------------------------------------------------------------- /src/renderer/components/CopyText.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 56 | 57 | 110 | -------------------------------------------------------------------------------- /src/renderer/components/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 48 | 49 | 98 | -------------------------------------------------------------------------------- /src/renderer/components/DexInput.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 70 | 71 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/renderer/components/Form.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 26 | 27 | -------------------------------------------------------------------------------- /src/renderer/components/History.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/renderer/components/Input.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 99 | 100 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /src/renderer/components/Login.vue: -------------------------------------------------------------------------------- 1 | 16 | 35 | 36 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/renderer/components/Radio.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 44 | -------------------------------------------------------------------------------- /src/renderer/components/RequestErrorMessage.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 31 | 32 | 60 | 61 | -------------------------------------------------------------------------------- /src/renderer/components/Settings.vue: -------------------------------------------------------------------------------- 1 | 17 | 37 | 38 | 70 | 71 | -------------------------------------------------------------------------------- /src/renderer/components/TimestampFromNow.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 47 | -------------------------------------------------------------------------------- /src/renderer/components/TokenIcon.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 59 | 60 | 61 | 95 | -------------------------------------------------------------------------------- /src/renderer/components/TransactionsSidebar.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 57 | 58 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /src/renderer/components/Zoom.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 34 | 35 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/renderer/components/charts/LineChart.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 50 | 51 | -------------------------------------------------------------------------------- /src/renderer/components/charts/SimpleDonut.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 51 | 52 | 94 | -------------------------------------------------------------------------------- /src/renderer/components/dashboard/ClaimGasButton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 30 | 31 | 55 | 56 | -------------------------------------------------------------------------------- /src/renderer/components/dashboard/Contacts.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 39 | 40 | 119 | -------------------------------------------------------------------------------- /src/renderer/components/dashboard/RecentTransactions.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 74 | 75 | 121 | -------------------------------------------------------------------------------- /src/renderer/components/dashboard/TopRightTile.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 17 | -------------------------------------------------------------------------------- /src/renderer/components/history/Search.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 80 | 81 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/renderer/components/login/CreateWallet.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 58 | 59 | 85 | -------------------------------------------------------------------------------- /src/renderer/components/login/EncryptedKey.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 51 | 52 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/renderer/components/login/Landing.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/renderer/components/login/Ledger.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 91 | 92 | 108 | 109 | -------------------------------------------------------------------------------- /src/renderer/components/login/LoginFormWrapper.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/renderer/components/login/Logo.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | 48 | 49 | -------------------------------------------------------------------------------- /src/renderer/components/login/Menu.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 29 | 30 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/renderer/components/login/PrivateKey.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 48 | 49 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/renderer/components/login/PrivateKeySeedWords.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 51 | 52 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/renderer/components/login/SavedWallet.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 74 | 75 | 98 | -------------------------------------------------------------------------------- /src/renderer/components/modals/AddressModal.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 83 | 84 | 113 | -------------------------------------------------------------------------------- /src/renderer/components/modals/CommitInfo.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 35 | 36 | 37 | 111 | 112 | -------------------------------------------------------------------------------- /src/renderer/components/modals/ConfirmDismissKycModal.vue: -------------------------------------------------------------------------------- 1 | 10 | 45 | 73 | 74 | -------------------------------------------------------------------------------- /src/renderer/components/modals/DexDemoConfirmation.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 42 | 43 | 44 | 80 | 81 | -------------------------------------------------------------------------------- /src/renderer/components/modals/DexOutOfDate.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 29 | 30 | 61 | 62 | -------------------------------------------------------------------------------- /src/renderer/components/modals/FractureGasModal.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 78 | 115 | 116 | -------------------------------------------------------------------------------- /src/renderer/components/modals/ModalWrapper.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 31 | 32 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/renderer/components/modals/SendWithLedgerModal.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 36 | 37 | 38 | 64 | 65 | -------------------------------------------------------------------------------- /src/renderer/components/settings/WalletActions.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | 29 | 30 | 46 | -------------------------------------------------------------------------------- /src/renderer/constants.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable id-length */ 2 | import en from './l10n/en'; 3 | import de from './l10n/de'; 4 | import nl from './l10n/nl'; 5 | import cn from './l10n/cn'; 6 | import ko from './l10n/ko'; 7 | import jp from './l10n/jp'; 8 | import ru from './l10n/ru'; 9 | 10 | // i18n 11 | const messages = { 12 | en, 13 | de, 14 | nl, 15 | cn, 16 | ko, 17 | jp, 18 | ru, 19 | }; 20 | 21 | const languages = [{ 22 | label: 'English', 23 | value: 'en', 24 | }, { 25 | label: '中文', 26 | value: 'cn', 27 | }, { 28 | label: 'Deutsch', 29 | value: 'de', 30 | }, { 31 | label: '日本語', 32 | value: 'jp', 33 | }, { 34 | label: '한국어', 35 | value: 'ko', 36 | }, { 37 | label: 'Nederlands', 38 | value: 'nl', 39 | }, { 40 | label: 'Русский', 41 | value: 'ru', 42 | }]; 43 | 44 | const charts = { 45 | DEBOUNCE: 500, 46 | }; 47 | 48 | const claiming = { 49 | DEFAULT_CLAIM_BLOCKS: 4800, 50 | }; 51 | 52 | const database = { 53 | NAME: 'aphelion.db', 54 | }; 55 | 56 | const defaultSettings = { 57 | CURRENCY: 'USD', 58 | STYLE: 'Day', 59 | }; 60 | 61 | const formats = { 62 | DATE: 'DD-MM-YYYY', 63 | DATE_SHORT: 'DD-MM', 64 | FRACTIONAL_NUMBER: '[.]0[00000000]', 65 | MONEY: '$0,0.00', 66 | TIME: 'HH:mm:ss', 67 | WEEKDAY_AND_TIME: 'dd H:ss', 68 | WHOLE_NUMBER: '0,0', 69 | WHOLE_NUMBER_NO_COMMAS: '0[.]0[00000000]', 70 | }; 71 | 72 | const intervals = { 73 | BLOCK: 20 * 1000, 74 | COMPLETE_SYSTEM_WITHDRAWALS: 15 * 60 * 1000, 75 | GAS_FRACTURE_NOTIFICATION: 4 * 60 * 1000, 76 | HOLDINGS_POLLING: 30 * 1000, 77 | MARKETS_POLLING: 5 * 60 * 1000, 78 | NETWORK_STATUS: 10 * 1000, 79 | REBROADCAST_TRANSACTIONS: 40 * 1000, 80 | TOKENS_POLLING: 15 * 60 * 1000, 81 | TOKENS_BALANCES_POLL_ALL: 5 * 60 * 1000, 82 | TRANSACTIONS_POLLING: 15 * 1000, 83 | WALLET_VERSION_CHECK: 10 * 60 * 1000, 84 | TICKER_POLLING: 2 * 60 * 1000, 85 | }; 86 | 87 | const loadStates = { 88 | FAILED: 'FAILED', 89 | LOADING: 'LOADING', 90 | READY: 'READY', 91 | }; 92 | 93 | const orders = { 94 | ALL_SWITCH: 'All', 95 | }; 96 | 97 | const requests = { 98 | FAILED: 'failed', 99 | PENDING: 'pending', 100 | SUCCESS: 'success', 101 | }; 102 | 103 | const timeouts = { 104 | BALANCE_PERSIST_FOR: 5 * 60 * 1000, 105 | CANCEL_ORDER: 5 * 60 * 1000, 106 | MONITOR_TRANSACTIONS: 10 * 60 * 1000, 107 | NEO_API_CALL: 500, 108 | RENDER_CHART: 100, 109 | RENDER_SPINNER: 2000, 110 | TRANSACTION: 5 * 60 * 1000, 111 | TRANSACTION_WITH_HARDWARE: 8 * 60 * 1000, 112 | WEBSOCKET_CONNECTION: 10 * 1000, 113 | }; 114 | 115 | export { 116 | charts, 117 | claiming, 118 | database, 119 | defaultSettings, 120 | formats, 121 | intervals, 122 | languages, 123 | loadStates, 124 | messages, 125 | orders, 126 | requests, 127 | timeouts, 128 | }; 129 | -------------------------------------------------------------------------------- /src/renderer/decorators/constants.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | Vue.prototype.$constants = require('@/constants'); 4 | -------------------------------------------------------------------------------- /src/renderer/decorators/index.js: -------------------------------------------------------------------------------- 1 | import './constants'; 2 | import './services'; 3 | -------------------------------------------------------------------------------- /src/renderer/decorators/services.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import _ from 'lodash'; 3 | 4 | import * as services from '../services'; 5 | 6 | const $services = {}; 7 | 8 | _.each(services, (service, name) => { 9 | $services[name] = service; 10 | }); 11 | 12 | Vue.prototype.$services = $services; 13 | -------------------------------------------------------------------------------- /src/renderer/error-handler.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import _ from 'lodash'; 3 | 4 | const prev = Vue.config.errorHandler; 5 | const handler = (err, vm, info) => { 6 | // Do stuff here... 7 | 8 | if (_.isFunction(prev)) { 9 | prev.call(this, err, vm, info); 10 | } 11 | }; 12 | 13 | Vue.config.errorHandler = handler; 14 | -------------------------------------------------------------------------------- /src/renderer/libraries.js: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue'; 3 | 4 | Vue.prototype.$accounting = require('accounting'); 5 | Vue.prototype.$lodash = require('lodash'); 6 | Vue.prototype.$moment = require('moment'); 7 | Vue.prototype.$numeral = require('numeral'); 8 | -------------------------------------------------------------------------------- /src/renderer/main.js: -------------------------------------------------------------------------------- 1 | import DomPortal from 'vue-dom-portal'; 2 | import Vue from 'vue'; 3 | import VueFlashMessage from 'vue-flash-message'; 4 | import VueI18n from 'vue-i18n'; 5 | import VueHighCharts from 'vue-highcharts'; 6 | import VueNativeSock from 'vue-native-websocket'; 7 | import _ from 'lodash'; 8 | import accounting from 'accounting'; 9 | import axios from 'axios'; 10 | import moment from 'moment'; 11 | 12 | // Services, etc. 13 | import { contacts, network, settings, storage, wallets } from '@/services'; 14 | 15 | // constants 16 | import { messages } from '@/constants'; 17 | 18 | // Initial Vue Libraries. 19 | import '@/error-handler'; 20 | import '@/libraries'; 21 | import '@/decorators'; 22 | import * as mixins from '@/mixins'; 23 | import App from '@/App'; 24 | import router from '@/router'; 25 | import { store } from '@/store'; 26 | 27 | // Global Vue Components. 28 | import CopyText from '@/components/CopyText'; 29 | import DatePicker from '@/components/DatePicker'; 30 | import DexInput from '@/components/DexInput'; 31 | import Form from '@/components/Form'; 32 | import Holding from '@/components/Holding'; 33 | import Icon from '@/components/Icon'; 34 | import Input from '@/components/Input'; 35 | import Radio from '@/components/Radio'; 36 | import Select from '@/components/Select'; 37 | import SimpleTransactions from '@/components/SimpleTransactions'; 38 | import SpinnerWrapper from '@/components/SpinnerWrapper'; 39 | import TimestampFromNow from '@/components/TimestampFromNow'; 40 | import TokenIcon from '@/components/TokenIcon'; 41 | 42 | // Global Libraries. 43 | window._ = _; 44 | window.accounting = accounting; 45 | window.axios = axios; 46 | window.moment = moment; 47 | window.TradingView = require('../../static/charting_library/charting_library.min').TradingView; 48 | 49 | // Setup Vue. 50 | if (!process.env.IS_WEB) Vue.use(require('vue-electron')); 51 | Vue.http = Vue.prototype.$http = axios; 52 | Vue.config.productionTip = false; 53 | 54 | // Vue Plugins. 55 | Vue.use(DomPortal); 56 | Vue.use(VueFlashMessage); 57 | Vue.use(VueHighCharts); 58 | Vue.use(VueI18n); 59 | require('vue-flash-message/dist/vue-flash-message.min.css'); 60 | 61 | Vue.use(VueNativeSock, network.getSelectedNetwork().websocketUri, { 62 | connectManually: true, 63 | format: 'json', 64 | reconnection: true, 65 | reconnectionDelay: 3000, 66 | store, 67 | }); 68 | 69 | // Register global mixins. 70 | _.each(mixins, (mixin) => { 71 | Vue.mixin(mixin); 72 | }); 73 | 74 | // Register global components. 75 | Vue.component('aph-copy-text', CopyText); 76 | Vue.component('aph-date-picker', DatePicker); 77 | Vue.component('aph-dex-input', DexInput); 78 | Vue.component('aph-form', Form); 79 | Vue.component('aph-holding', Holding); 80 | Vue.component('aph-icon', Icon); 81 | Vue.component('aph-input', Input); 82 | Vue.component('aph-radio', Radio); 83 | Vue.component('aph-select', Select); 84 | Vue.component('aph-simple-transactions', SimpleTransactions); 85 | Vue.component('aph-spinner-wrapper', SpinnerWrapper); 86 | Vue.component('aph-timestamp-from-now', TimestampFromNow); 87 | Vue.component('aph-token-icon', TokenIcon); 88 | 89 | // Sync local storage to store. 90 | storage.init(); 91 | contacts.sync(); 92 | network.init(); 93 | settings.sync(); 94 | wallets.sync(); 95 | 96 | // get user's locale settings 97 | const language = localStorage.getItem('language') || 98 | (window.navigator.userLanguage || 99 | window.navigator.language).split('-')[0]; 100 | 101 | // Create VueI18n instance with options 102 | const i18n = new VueI18n({ 103 | locale: language, 104 | fallbackLocale: 'en', 105 | messages, 106 | }); 107 | 108 | /* eslint-disable no-new */ 109 | new Vue({ 110 | router, 111 | store, 112 | i18n, 113 | ...App, 114 | }).$mount('#app'); 115 | -------------------------------------------------------------------------------- /src/renderer/mixins/alerts.js: -------------------------------------------------------------------------------- 1 | export default { 2 | isAnObject: true, 3 | }; 4 | -------------------------------------------------------------------------------- /src/renderer/mixins/auth.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/mixins/auth.js -------------------------------------------------------------------------------- /src/renderer/mixins/formatting.js: -------------------------------------------------------------------------------- 1 | import { formatting } from '../services'; 2 | 3 | export default { 4 | methods: { 5 | $abbreviateNumber(...args) { 6 | return formatting.abbreviateNumber.apply(null, args); 7 | }, 8 | 9 | $formatDate(...args) { 10 | return formatting.formatDate.apply(null, args); 11 | }, 12 | 13 | $formatDateShort(...args) { 14 | return formatting.formatDateShort.apply(null, args); 15 | }, 16 | 17 | $formatMoney(...args) { 18 | return formatting.formatMoney.apply(null, args); 19 | }, 20 | 21 | $formatMoneyWithoutCents(...args) { 22 | return formatting.formatMoneyWithoutCents.apply(null, args); 23 | }, 24 | 25 | $formatNumber(...args) { 26 | return formatting.formatNumber.apply(null, args); 27 | }, 28 | 29 | $formatTime(...args) { 30 | return formatting.formatTime.apply(null, args); 31 | }, 32 | 33 | $formatWeekdayAndTime(...args) { 34 | return formatting.formatWeekdayAndTime.apply(null, args); 35 | }, 36 | 37 | $formatTokenAmount(...args) { 38 | return formatting.formatTokenAmount.apply(null, args); 39 | }, 40 | 41 | $cleanAmount(...args) { 42 | return formatting.cleanAmount.apply(null, args); 43 | }, 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /src/renderer/mixins/index.js: -------------------------------------------------------------------------------- 1 | export { default as alerts } from './alerts'; 2 | export { default as auth } from './auth'; 3 | export { default as formatting } from './formatting'; 4 | export { default as online } from './online'; 5 | export { default as requests } from './requests'; 6 | -------------------------------------------------------------------------------- /src/renderer/mixins/online.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/src/renderer/mixins/online.js -------------------------------------------------------------------------------- /src/renderer/mixins/requests.js: -------------------------------------------------------------------------------- 1 | export default { 2 | methods: { 3 | $isDone(identifier) { 4 | return _.get(this.$store.state.requests, `${identifier}.status`) === this.$constants.requests.SUCCESS; 5 | }, 6 | 7 | $isFailed(identifier) { 8 | return _.get(this.$store.state.requests, `${identifier}.status`) === this.$constants.requests.FAILED; 9 | }, 10 | 11 | $isPending(identifier) { 12 | return _.get(this.$store.state.requests, `${identifier}.status`) === this.$constants.requests.PENDING; 13 | }, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/renderer/services/alerts.js: -------------------------------------------------------------------------------- 1 | /** eslint-disable no-use-before-define */ 2 | import Vue from 'vue'; 3 | import _ from 'lodash'; 4 | 5 | import { store } from '../store'; 6 | 7 | const MILLISECONDS_PER_WORD = 750; 8 | const NETWORK_ERROR_THRESHOLD_SECONDS = 60; 9 | 10 | function countWords(str) { 11 | return str.trim().split(/\s+/).length; 12 | } 13 | 14 | function calculateTimeout(str) { 15 | return countWords(str) * MILLISECONDS_PER_WORD; 16 | } 17 | 18 | function errorAlreadyExists(content) { 19 | return !!_.find(Vue.prototype.$flashStorage.storage, (item) => { 20 | return item.type === 'error' && item.content === content; 21 | }); 22 | } 23 | 24 | function shouldHideNetworkError() { 25 | return moment.utc().diff(moment.unix(store.state.lastReceivedBlock), 'seconds') < NETWORK_ERROR_THRESHOLD_SECONDS; 26 | } 27 | 28 | export default { 29 | 30 | success(message) { 31 | Vue.prototype.$flashStorage.flash(message, 'success', { 32 | timeout: calculateTimeout(message), 33 | }); 34 | }, 35 | 36 | info(message) { 37 | Vue.prototype.$flashStorage.flash(message, 'info', { 38 | timeout: calculateTimeout(message), 39 | }); 40 | }, 41 | 42 | warning(message) { 43 | Vue.prototype.$flashStorage.flash(message, 'warning', { 44 | timeout: calculateTimeout(message), 45 | }); 46 | }, 47 | 48 | error(message) { 49 | if (errorAlreadyExists(message)) { 50 | return; 51 | } 52 | 53 | Vue.prototype.$flashStorage.flash(message, 'error', { 54 | timeout: calculateTimeout(message), 55 | }); 56 | }, 57 | 58 | exception(e) { 59 | console.log(e); 60 | if (!e.message) { 61 | this.error(e); 62 | } else { 63 | if (e.message === 'Network Error') { 64 | // absorb these errors, so we don't constantly alert the user if they are not online 65 | // maybe some other kind of offline indicator? 66 | return; 67 | } 68 | this.error(e.message); 69 | } 70 | }, 71 | 72 | networkException(message) { 73 | if (shouldHideNetworkError()) { 74 | return; 75 | } 76 | 77 | this.exception(message); 78 | }, 79 | 80 | }; 81 | -------------------------------------------------------------------------------- /src/renderer/services/contacts.js: -------------------------------------------------------------------------------- 1 | import { store } from '../store'; 2 | import storage from './storage'; 3 | 4 | const CONTACTS_STORAGE_KEY = 'contacts'; 5 | 6 | export default { 7 | 8 | add(address, data) { 9 | const contacts = this.getAll(); 10 | storage.set(CONTACTS_STORAGE_KEY, _.set(contacts, this.cleanForKey(address), data)); 11 | 12 | return this; 13 | }, 14 | 15 | remove(address) { 16 | const contacts = this.getAll(); 17 | storage.set(CONTACTS_STORAGE_KEY, _.omit(contacts, this.cleanForKey(address))); 18 | 19 | return this; 20 | }, 21 | 22 | getAll() { 23 | return storage.get(CONTACTS_STORAGE_KEY, {}); 24 | }, 25 | 26 | getAllAsArray() { 27 | return _.sortBy(_.values(this.getAll()), 'name'); 28 | }, 29 | 30 | getOne(name) { 31 | return _.find(this.getAllAsArray(), { name }); 32 | }, 33 | 34 | cleanForKey(key) { 35 | return key.trim().replace('.', '_').replace('[', '').replace(']', ''); 36 | }, 37 | 38 | contactExists(name) { 39 | return !!this.getOne(name.trim()); 40 | }, 41 | 42 | findContactByAddress(address) { 43 | return _.find(this.getAllAsArray(), { address }); 44 | }, 45 | 46 | sync() { 47 | store.commit('setContacts', this.getAllAsArray()); 48 | }, 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /src/renderer/services/db.js: -------------------------------------------------------------------------------- 1 | import ipcPromise from 'ipc-promise'; 2 | import _ from 'lodash'; 3 | 4 | function formatResponse(response, defaultValue) { 5 | return _.get(response, 'data', defaultValue); 6 | } 7 | 8 | export default { 9 | async get(id, defaultValue = null) { 10 | try { 11 | const response = await ipcPromise.send('db.get', id); 12 | return Promise.resolve(formatResponse(response, defaultValue)); 13 | } catch (e) { 14 | return Promise.resolve(defaultValue); 15 | } 16 | }, 17 | 18 | async remove(id) { 19 | try { 20 | await ipcPromise.send('db.remove', id); 21 | } catch (e) { 22 | console.log(e); 23 | } 24 | }, 25 | 26 | async upsert(id, data) { 27 | try { 28 | await ipcPromise.send('db.upsert', { id, data }); 29 | } catch (e) { 30 | console.log(e); 31 | } 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /src/renderer/services/ethclient.js: -------------------------------------------------------------------------------- 1 | /* ************************************************************************************** 2 | * Documentation About etherscan api is available at follwing link: 3 | * https://etherscan.io/apis 4 | * 5 | ************************************************************************************** */ 6 | import alerts from './alerts'; 7 | 8 | export default { 9 | getLast50TxByAddress(uri, address) { 10 | return new Promise((resolve, reject) => { 11 | try { 12 | return axios.get(`${uri}&module=account&action=txlist&address=${address}` 13 | + '&startblock=0&endblock=99999999&page=1&offset=50&sort=desc') 14 | .then((res) => { 15 | resolve(res.data.result); 16 | }).catch((e) => { 17 | alerts.exception(e); 18 | resolve([]); 19 | }); 20 | } catch (e) { 21 | alerts.exception(e); 22 | return reject(e); 23 | } 24 | }); 25 | }, 26 | 27 | getLast50TokenTxByAddress(uri, address) { 28 | return new Promise((resolve, reject) => { 29 | try { 30 | return axios.get(`${uri}&module=account&action=tokentx&address=${address}` 31 | + '&startblock=0&endblock=99999999&page=1&offset=50&sort=desc') 32 | .then((res) => { 33 | resolve(res.data.result); 34 | }).catch((e) => { 35 | alerts.exception(e); 36 | resolve([]); 37 | }); 38 | } catch (e) { 39 | alerts.exception(e); 40 | return reject(e); 41 | } 42 | }); 43 | }, 44 | 45 | getAbiByAddress(uri, address) { 46 | return new Promise((resolve, reject) => { 47 | try { 48 | return axios.get(`${uri}&module=contract&action=getabi&address=${address}`) 49 | .then((res) => { 50 | if (res.data.status === '0') { 51 | resolve([]); 52 | } else { 53 | resolve(res.data.result); 54 | } 55 | }).catch((e) => { 56 | alerts.exception(e); 57 | resolve([]); 58 | }); 59 | } catch (e) { 60 | alerts.exception(e); 61 | return reject(e); 62 | } 63 | }); 64 | }, 65 | 66 | getTokenInfo(address) { 67 | return new Promise((resolve, reject) => { 68 | try { 69 | return axios.get(`http://api.ethplorer.io/getTokenInfo/${address}?apiKey=freekey`) 70 | .then((res) => { 71 | if (res.data.error) { 72 | return reject(res.data.error.message); 73 | } 74 | return resolve(res.data); 75 | }).catch((e) => { 76 | alerts.exception(e); 77 | return reject(e); 78 | }); 79 | } catch (e) { 80 | alerts.exception(e); 81 | return reject(e); 82 | } 83 | }); 84 | }, 85 | }; 86 | -------------------------------------------------------------------------------- /src/renderer/services/index.js: -------------------------------------------------------------------------------- 1 | import alerts from './alerts'; 2 | import assets from './assets'; 3 | import contacts from './contacts'; 4 | import db from './db'; 5 | import formatting from './formatting'; 6 | import ledger from './ledger'; 7 | import neo from './neo'; 8 | import bwclient from './bwclient'; 9 | import network from './network'; 10 | import settings from './settings'; 11 | import storage from './storage'; 12 | import valuation from './valuation'; 13 | import wallets from './wallets'; 14 | import dex from './dex'; 15 | 16 | export { 17 | alerts, 18 | assets, 19 | contacts, 20 | db, 21 | dex, 22 | formatting, 23 | ledger, 24 | neo, 25 | bwclient, 26 | network, 27 | settings, 28 | storage, 29 | valuation, 30 | wallets, 31 | }; 32 | -------------------------------------------------------------------------------- /src/renderer/services/settings.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import { defaultSettings } from '../constants'; 4 | import { store } from '../store'; 5 | import storage from './storage'; 6 | 7 | const SETTINGS_STORAGE_KEY = 'settings'; 8 | const CURRENCY_STORAGE_KEY = `${SETTINGS_STORAGE_KEY}.currency`; 9 | const CURRENCY_SYMBOL_STORAGE_KEY = `${SETTINGS_STORAGE_KEY}.currencySymbol`; 10 | const CURRENCIES = { 11 | USD: { 12 | label: 'USD', 13 | symbol: '$', 14 | value: 'USD', 15 | }, 16 | EUR: { 17 | label: 'EUR', 18 | symbol: '€', 19 | value: 'EUR', 20 | }, 21 | JPY: { 22 | label: 'JPY', 23 | symbol: '¥', 24 | value: 'JPY', 25 | }, 26 | GBP: { 27 | label: 'GBP', 28 | symbol: '£', 29 | value: 'GBP', 30 | }, 31 | CHF: { 32 | label: 'CHF', 33 | symbol: null, 34 | value: 'CHF', 35 | }, 36 | CAD: { 37 | label: 'CAD', 38 | symbol: '$', 39 | value: 'CAD', 40 | }, 41 | AUD: { 42 | label: 'AUD', 43 | symbol: '$', 44 | value: 'AUD', 45 | }, 46 | }; 47 | const GAS_FRACTURE_STORAGE_KEY = `${SETTINGS_STORAGE_KEY}.gasFracture`; 48 | const STYLE_MODE_STORAGE_KEY = `${SETTINGS_STORAGE_KEY}.style`; 49 | 50 | export default { 51 | 52 | getCurrencies() { 53 | return CURRENCIES; 54 | }, 55 | 56 | getCurrenciesAsArray() { 57 | return _.sortBy(_.values(CURRENCIES), 'label'); 58 | }, 59 | 60 | getCurrency() { 61 | return storage.get(CURRENCY_STORAGE_KEY, defaultSettings.CURRENCY); 62 | }, 63 | 64 | getCurrencySymbol() { 65 | return CURRENCIES[this.getCurrency()].symbol; 66 | }, 67 | 68 | setCurrency(currency) { 69 | storage.set(CURRENCY_STORAGE_KEY, currency); 70 | this.setCurrencySymbol(this.getCurrencySymbol()); 71 | this.sync(); 72 | 73 | return this; 74 | }, 75 | 76 | setCurrencySymbol(currencySymbol) { 77 | storage.set(CURRENCY_SYMBOL_STORAGE_KEY, currencySymbol); 78 | 79 | return this; 80 | }, 81 | 82 | sync() { 83 | store.commit('setCurrency', this.getCurrency()); 84 | store.commit('setCurrencySymbol', this.getCurrencySymbol()); 85 | store.commit('setStyleMode', this.getStyleMode()); 86 | store.commit('setGasFracture', this.getGasFracture()); 87 | }, 88 | 89 | getStyleMode() { 90 | return storage.get(STYLE_MODE_STORAGE_KEY, defaultSettings.STYLE); 91 | }, 92 | 93 | setStyleMode(style) { 94 | storage.set(STYLE_MODE_STORAGE_KEY, style); 95 | this.sync(); 96 | 97 | return this; 98 | }, 99 | 100 | getGasFracture() { 101 | return storage.get(GAS_FRACTURE_STORAGE_KEY, null); 102 | }, 103 | 104 | setGasFracture(fracture) { 105 | storage.set(GAS_FRACTURE_STORAGE_KEY, fracture); 106 | this.sync(); 107 | 108 | return this; 109 | }, 110 | 111 | toggleGasFracture() { 112 | storage.set(GAS_FRACTURE_STORAGE_KEY, !this.getGasFracture()); 113 | this.sync(); 114 | 115 | return this; 116 | }, 117 | 118 | }; 119 | -------------------------------------------------------------------------------- /src/renderer/services/storage.js: -------------------------------------------------------------------------------- 1 | import Store from 'electron-store'; 2 | import _ from 'lodash'; 3 | import { ipcRenderer } from 'electron'; 4 | 5 | let store; 6 | let localStore; 7 | 8 | export default { 9 | clean() { 10 | localStore = ipcRenderer.sendSync('storage.clean'); 11 | }, 12 | 13 | delete(key) { 14 | localStore = _.omit(localStore, key); 15 | ipcRenderer.send('storage.delete', key); 16 | 17 | return this; 18 | }, 19 | 20 | get(key, defaultValue = null) { 21 | return _.get(localStore, key, defaultValue); 22 | }, 23 | 24 | has(key) { 25 | return _.has(localStore, key); 26 | }, 27 | 28 | init() { 29 | store = new Store(); 30 | localStore = store.store; 31 | 32 | this.clean(); 33 | }, 34 | 35 | path() { 36 | return store.path; 37 | }, 38 | 39 | set(key, value) { 40 | _.set(localStore, key, value); 41 | ipcRenderer.send('storage.set', key, value); 42 | 43 | return this; 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /src/renderer/services/storageNew.js: -------------------------------------------------------------------------------- 1 | import { store } from '../store'; 2 | import storage from './storage'; 3 | 4 | const WALLETS_STORAGE_KEY_NEW = 'wallets_new'; 5 | 6 | 7 | export default { 8 | 9 | add(name, data) { 10 | storage.set(WALLETS_STORAGE_KEY_NEW, _.set(this.getAll(), this.cleanForKey(name), data)); 11 | return this; 12 | }, 13 | 14 | remove(name) { 15 | return new Promise((resolve, reject) => { 16 | try { 17 | storage.set(WALLETS_STORAGE_KEY_NEW, _.omit(this.getAll(), this.cleanForKey(name))); 18 | return resolve(); 19 | } catch (e) { 20 | return reject('Unable to delete wallet'); 21 | } 22 | }); 23 | }, 24 | 25 | cleanForKey(key) { 26 | return key.trim().replace('.', '_').replace('[', '').replace(']', ''); 27 | }, 28 | 29 | cleanBadWalletValues() { 30 | const wallets = this.getAll(); 31 | const keys = Object.keys(wallets); 32 | const values = Object.values(wallets); 33 | for (let i = 0; i < keys.length; i += 1) { 34 | if (!values[i].label) { 35 | storage.set(WALLETS_STORAGE_KEY_NEW, _.omit(wallets, keys[i])); 36 | } 37 | } 38 | }, 39 | 40 | getOne(label) { 41 | return _.find(this.getAllAsArray(), { label }); 42 | }, 43 | 44 | getAll() { 45 | return storage.get(WALLETS_STORAGE_KEY_NEW, {}); 46 | }, 47 | 48 | getAllAsArray() { 49 | return _.sortBy(_.values(this.getAll()), 'label'); 50 | }, 51 | 52 | walletExists(name) { 53 | return !!this.getOne(name.trim()); 54 | }, 55 | 56 | sync() { 57 | store.commit('setWalletsNew', this.getAllAsArray()); 58 | }, 59 | 60 | }; 61 | -------------------------------------------------------------------------------- /src/renderer/shared-components/index.js: -------------------------------------------------------------------------------- 1 | // import SomeSharedComponent from './SomeSharedComponent.vue'; 2 | 3 | export { 4 | // SomeSharedComponent, 5 | }; 6 | -------------------------------------------------------------------------------- /src/renderer/store/getters.js: -------------------------------------------------------------------------------- 1 | export const acceptCommitInfo = state => state.acceptCommitInfo; 2 | export const acceptDexDemoVersion = state => state.acceptDexDemoVersion[state.currentNetwork.net]; 3 | export const acceptDexOutOfDate = state => state.acceptDexOutOfDate; 4 | export const activeTransaction = state => state.activeTransaction; 5 | export const claimModalModel = state => state.claimModalModel; 6 | export const commitModalModel = state => state.commitModalModel; 7 | export const commitState = state => state.commitState; 8 | export const contacts = state => state.contacts; 9 | export const currency = state => state.currency; 10 | export const currencySymbol = state => state.currencySymbol; 11 | export const currentEditContact = state => state.currentEditContact; 12 | export const currentLoginToWallet = state => state.currentLoginToWallet; 13 | export const currentNetwork = state => state.currentNetwork; 14 | export const currentWallet = state => state.currentWallet; 15 | export const depositWithdrawModalModel = state => state.depositWithdrawModalModel; 16 | export const fractureGasModalModel = state => state.fractureGasModalModel; 17 | export const holdings = state => state.holdings; 18 | export const lastReceivedBlock = state => state.lastReceivedBlock; 19 | export const lastSuccessfulRequest = state => state.lastSuccessfulRequest; 20 | export const latestVersion = state => state.latestVersion; 21 | export const markets = state => state.markets; 22 | export const menuCollapsed = state => state.menuCollapsed; 23 | export const menuToggleable = state => state.menuToggleable; 24 | export const nep5Balances = state => state.nep5Balances; 25 | export const orderBook = state => state.orderBook; 26 | export const orderHistory = state => state.orderHistory; 27 | export const orderToConfirm = state => state.orderToConfirm; 28 | export const ordersToShow = state => state.ordersToShow; 29 | export const portfolio = state => state.portfolio; 30 | export const recentTransactions = state => state.recentTransactions; 31 | export const requests = state => state.requests; 32 | export const searchTransactionFromDate = state => state.searchTransactionFromDate; 33 | export const searchTransactionToDate = state => state.searchTransactionToDate; 34 | export const searchTransactions = state => state.searchTransactions; 35 | export const sendInProgress = state => state.sendInProgress[state.currentNetwork.net]; 36 | export const sendModel = state => state.sendModel[state.currentNetwork.net]; 37 | export const showAddContactModal = state => state.showAddContactModal; 38 | export const showAddTokenModal = state => state.showAddTokenModal; 39 | export const showLearnMore = state => state.showLearnMore; 40 | export const showOrderConfirmationModal = state => state.showOrderConfirmationModal; 41 | export const showPortfolioHeader = state => state.showPortfolioHeader; 42 | export const showSendAddressModal = state => state.showSendAddressModal; 43 | export const showWalletBackupModal = state => state.showWalletBackupModal; 44 | export const showWalletBackupModalBTC = state => state.showWalletBackupModalBTC; 45 | export const statsToken = state => state.statsToken; 46 | export const tradeHistory = state => state.tradeHistory; 47 | export const transactionDetails = state => state.transactionDetails; 48 | export const version = state => state.version; 49 | export const wallets = state => state.wallets; 50 | export const websocketUri = state => _.get(state.currentNetwork, 'websocketUri'); 51 | export const tickerData = (state) => { 52 | return state.currentMarket ? state.tickerDataByMarket[state.currentMarket.marketName] : {}; 53 | }; 54 | -------------------------------------------------------------------------------- /src/renderer/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import moment from 'moment'; 4 | 5 | import * as actions from './actions'; 6 | import * as getters from './getters'; 7 | import * as mutations from './mutations'; 8 | 9 | Vue.use(Vuex); 10 | 11 | const pjson = require('../../../package.json'); 12 | 13 | const state = { 14 | acceptCommitInfo: false, 15 | acceptDexDemoVersion: {}, 16 | acceptDexOutOfDate: false, 17 | activeTransaction: null, 18 | blockDetails: {}, 19 | claimModalModel: null, 20 | commitChangeInProgress: null, 21 | commitModalModel: null, 22 | commitState: null, 23 | confirmDismissKyc: false, 24 | contacts: [], 25 | currency: null, 26 | currencySymbol: null, 27 | currentEditContact: null, 28 | currentLoginToWallet: null, 29 | currentMarket: null, 30 | currentNetwork: null, 31 | currentWallet: null, 32 | depositWithdrawModalModel: null, 33 | fractureGasModalModel: null, 34 | gasClaim: null, 35 | gasFracture: null, 36 | holdings: [], 37 | kycInProgressModalModel: null, 38 | lastReceivedBlock: null, 39 | lastSuccessfulRequest: null, 40 | latestVersion: null, 41 | markets: [], 42 | menuToggleable: false, 43 | menuCollapsed: true, 44 | needsWsReconnectHandling: false, 45 | nep5Balances: {}, 46 | orderBook: null, 47 | orderHistory: null, 48 | orderPrice: '', 49 | orderQuantity: '', 50 | orderToConfirm: false, 51 | ordersToShow: '', 52 | portfolio: null, 53 | recentTransactions: [], 54 | requests: {}, 55 | searchTransactionFromDate: moment().startOf('day').subtract(7, 'days'), 56 | searchTransactionToDate: null, 57 | searchTransactions: [], 58 | sendInProgress: {}, 59 | sendModel: {}, 60 | showAddContactModal: false, 61 | showAddTokenModal: false, 62 | showClaimGasModal: false, 63 | showImportAWalletModal: false, 64 | showLearnMore: false, 65 | showLoginToWalletModal: false, 66 | showOrderConfirmationModal: false, 67 | showPortfolioHeader: true, 68 | showSummaryTile: true, 69 | showSendAddressModal: false, 70 | showSendRequestLedgerSignature: false, 71 | showSendWithLedgerModal: false, 72 | showWalletBackupModal: false, 73 | showWalletBackupModalBTC: false, 74 | socket: { 75 | lastMessage: null, 76 | isConnected: false, 77 | client: null, 78 | reconnectError: false, 79 | }, 80 | statsToken: null, 81 | styleMode: 'Night', 82 | systemWithdraw: null, 83 | tradeHistory: null, 84 | transactionDetails: {}, 85 | tickerDataByMarket: {}, 86 | version: pjson.version, 87 | wallets: [], 88 | walletsNew: [], 89 | withdrawInProgressModalModel: null, 90 | }; 91 | 92 | const store = new Vuex.Store({ 93 | actions, 94 | getters, 95 | mutations, 96 | state, 97 | }); 98 | 99 | export { 100 | actions, 101 | getters, 102 | mutations, 103 | state, 104 | store, 105 | }; 106 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/.gitkeep -------------------------------------------------------------------------------- /static/charting_library/static/bundles/crosshair.6c091f7d5427d0c5e6d9dc3a90eb2b20.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/bundles/crosshair.6c091f7d5427d0c5e6d9dc3a90eb2b20.cur -------------------------------------------------------------------------------- /static/charting_library/static/bundles/dot.ed68e83c16f77203e73dbc4c3a7c7fa1.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/bundles/dot.ed68e83c16f77203e73dbc4c3a7c7fa1.cur -------------------------------------------------------------------------------- /static/charting_library/static/bundles/eraser.0579d40b812fa2c3ffe72e5803a6e14c.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/bundles/eraser.0579d40b812fa2c3ffe72e5803a6e14c.cur -------------------------------------------------------------------------------- /static/charting_library/static/bundles/grab.bc156522a6b55a60be9fae15c14b66c5.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/bundles/grab.bc156522a6b55a60be9fae15c14b66c5.cur -------------------------------------------------------------------------------- /static/charting_library/static/bundles/grabbing.1c0862a8a8c0fb02885557bc97fdafe7.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/bundles/grabbing.1c0862a8a8c0fb02885557bc97fdafe7.cur -------------------------------------------------------------------------------- /static/charting_library/static/bundles/ie-fallback-logos.b27f679ee44b7d0992e1.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([10],{695:function(A,h,i){"use strict";Object.defineProperty(h,"__esModule",{value:!0}),h.fallbackImages={tvLogoBlack:i(1349),tvLogoWhite:i(1350)},h.logoSizes={benzingapro:{width:135,height:25},bovespa:{width:135,height:50},cme:{width:175,height:26},currencywiki:{width:135,height:25},dailyfx:{width:135,height:25},fxstreet:{width:137,height:33},investopedia:{width:135,height:23},smartlab:{width:135,height:37},lse:{width:135,height:31},arabictrader:{width:135,height:40},goldprice:{width:135,height:27},silverprice:{width:135,height:27},inbestia:{width:195,height:50},immfx:{width:122,height:26},kitco:{width:130,height:35},enbourse:{width:135,height:40},rankia:{width:65,height:17},stockwatch:{width:135,height:19},tradecapitan:{width:121,height:45}}},1349:function(A,h){A.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAAmCAMAAACmhKjHAAAAXVBMVEUAAAAAAAAAAAAFEhgrg6g4rNsznskLIy0AAAAQMkAdWXIAAAAxlb4UQFEAAAAAAAAAAAAkcI8ujbQgZYEZTWMAAAAAAAAAAAA2pNIAAAAAAAAAAAAoe50AAAA7s+Q2ucaKAAAAHnRSTlMAmU2f2fnspiWswAnms3xCE8zfxrmPhjfybV9W0hyxWOJtAAABrElEQVRIx8WVbbOCIBCFrwmKCpnvlsb//5mXXcrlxcpm7sw9nwx4hrPLgX7+XBchxPdQfU2srlP1BXZLXC1H0WlIfI3HLC+4OC+ZlG1TWnQ6wN0QY/ohzlIYqC+fuBMsa7Qj3lu/71kBa5j2VSZWpzfgmbgd8ly9bKiZ7XUsLrscyVd24dhnva8VujRU+3kxU6V+pbkw07cYE+cE1MKaVql2x7CxO4ZY9YwZcvARkwy81gFnt0sVtkbBt4o5lN8f5MqMLBFInNU1zGcKGHLQBPztKksxi8as286Iy3MzwkMulStsWXnHJ50VKUNnBQ+4TEs/QANURCvy7JEzRQeBHJwlkk6yGXHqsVEPaSD3xUw9miihdlQartNOsStx3OnuSHfQjtnyNjK1Tnrinqd830BuuTwLj4Dh81EShw0SW40SOeXMb9kLkz/DU4LgHV+LbiuPBIPxFUUQNcKrBuVFahBs/AyhVRTcQyovDqiMXDzvxpDYzscqyCl1jG6lIEOhWMN8rtic0jO8Sv1BWQehXbwH/JjiV7IejlHxv1e1jIe2o/pI9+n0XjVQ/6ZfnFlWaxVUZmcAAAAASUVORK5CYII="},1350:function(A,h){A.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAAmCAMAAACmhKjHAAAAYFBMVEUAAAD////////q9/1ux+tSvOfZ8fr////I6vid2fL///9bwOm45Pb///////////+E0O9jw+mQ1fCq3vT///////9KuOb///////////94y+3///////////////87s+R/+BgSAAAAH3RSTlMAmU2f2eymJazACeazfEITzN/GuY+G8l9WOdJyaRwwr8L7/gAAAaRJREFUSMfFld2SgyAMhZeCP4i11qpV2y7v/5ZLwrgBYls7szN7rhT5hpOQxK8/16kois+h5ia8bnP1AXYVoaa96NyLWMM+y5MA5VoZc261R+cd3BUxZVcpCQvN6R13gG2tDXXxfl+zBexRNpYWXocX4JG4DfJYPU2o+3qxGzJdjuQzu3Dto93WAlnqq+16cZ+0faaxdJ+vHCuOAnSGPee6Pm+gzu6QYtVaZsjBAycVeG0Szh8na0xNDc8151BxfpDTGVkiMOHEPa1PCRgKkoDvoTKJtejMhulkXJ67FcZJs8CRdCV392qCHVKhszLlMmviAuohItqR4+E6DDNHDu4SyaCyFXE1dYUO3Jcj5WimCvWrxnGdDYJdiAuzO1AP+jUMjyS9kwtx6y0/IlBBeGkqVavjCsYEFb8xGuDYpWPtJZwdYZQg+MBp0VF4JLfIWxRB1ABTDcJjagWfQRlaRUEfUni8QA1zsfZGL3zmuUrmNJNBVxZkKJVqVcyV4DQZw4uxb5R1ULRTNMD3iU/Jpt9H8b9XNQ27jqP4SI/vw2s1QP2bfgDhqloD84hV5AAAAABJRU5ErkJggg=="}}); -------------------------------------------------------------------------------- /static/charting_library/static/bundles/propertypagesfactory.54b21a18753b2d8c83c2.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([11],{162:function(e,r){"use strict";r.createInputsPropertyPage=function(e,r){var t=e.getInputsPropertyPage();return null==t?null:new t(e.properties(),r,e)},r.createStudyStrategyPropertyPage=function(e,r){var t=e.getStrategyPropertyPage();return null==t?null:new t(e.properties(),r,e)},r.createStylesPropertyPage=function(e,r){var t=e.getStylesPropertyPage();return null==t?null:new t(e.properties(),r,e)},r.createDisplayPropertyPage=function(e,r){var t=e.getDisplayPropertyPage();return null==t?null:new t(e.properties(),r,e)},r.createVisibilitiesPropertyPage=function(e,r){var t=e.getVisibilitiesPropertyPage();return null==t?null:new t(e.properties(),r,e)},r.hasInputsPropertyPage=function(e){return null!==e.getInputsPropertyPage()},r.hasStylesPropertyPage=function(e){return null!==e.getStylesPropertyPage()}}}); -------------------------------------------------------------------------------- /static/charting_library/static/bundles/vendors.a94ef44ed5c201cefcf6ad7460788c1a.css: -------------------------------------------------------------------------------- 1 | @keyframes highlight-animation{0%{background:transparent}to{background:#fff2cf}}@keyframes highlight-animation-theme-dark{0%{background:transparent}to{background:#194453}} -------------------------------------------------------------------------------- /static/charting_library/static/bundles/zoom.e21f24dd632c7069139bc47ae89c54b5.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/bundles/zoom.e21f24dd632c7069139bc47ae89c54b5.cur -------------------------------------------------------------------------------- /static/charting_library/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/charting_library/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/charting_library/static/images/balloon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/balloon.png -------------------------------------------------------------------------------- /static/charting_library/static/images/bar-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/bar-loader.gif -------------------------------------------------------------------------------- /static/charting_library/static/images/button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/button-bg.png -------------------------------------------------------------------------------- /static/charting_library/static/images/charting_library/logo-widget-copyright-faded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/charting_library/logo-widget-copyright-faded.png -------------------------------------------------------------------------------- /static/charting_library/static/images/charting_library/logo-widget-copyright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/charting_library/logo-widget-copyright.png -------------------------------------------------------------------------------- /static/charting_library/static/images/controlll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/controlll.png -------------------------------------------------------------------------------- /static/charting_library/static/images/delayed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/delayed.png -------------------------------------------------------------------------------- /static/charting_library/static/images/dialogs/checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/dialogs/checkbox.png -------------------------------------------------------------------------------- /static/charting_library/static/images/dialogs/close-flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/dialogs/close-flat.png -------------------------------------------------------------------------------- /static/charting_library/static/images/dialogs/large-slider-handle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/dialogs/large-slider-handle.png -------------------------------------------------------------------------------- /static/charting_library/static/images/dialogs/linewidth-slider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/dialogs/linewidth-slider.png -------------------------------------------------------------------------------- /static/charting_library/static/images/dialogs/opacity-slider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/dialogs/opacity-slider.png -------------------------------------------------------------------------------- /static/charting_library/static/images/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/icons.png -------------------------------------------------------------------------------- /static/charting_library/static/images/prediction-clock-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/prediction-clock-black.png -------------------------------------------------------------------------------- /static/charting_library/static/images/prediction-clock-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/prediction-clock-white.png -------------------------------------------------------------------------------- /static/charting_library/static/images/prediction-failure-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/prediction-failure-white.png -------------------------------------------------------------------------------- /static/charting_library/static/images/prediction-success-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/prediction-success-white.png -------------------------------------------------------------------------------- /static/charting_library/static/images/select-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/select-bg.png -------------------------------------------------------------------------------- /static/charting_library/static/images/sidetoolbar/instruments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/sidetoolbar/instruments.png -------------------------------------------------------------------------------- /static/charting_library/static/images/sidetoolbar/toolgroup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/sidetoolbar/toolgroup.png -------------------------------------------------------------------------------- /static/charting_library/static/images/svg/chart/bucket2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/charting_library/static/images/svg/chart/font.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/charting_library/static/images/svg/chart/large-slider-handle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/charting_library/static/images/svg/chart/pencil2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/charting_library/static/images/svg/question-mark-rounded.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/charting_library/static/images/tvcolorpicker-bg-gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/tvcolorpicker-bg-gradient.png -------------------------------------------------------------------------------- /static/charting_library/static/images/tvcolorpicker-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/tvcolorpicker-bg.png -------------------------------------------------------------------------------- /static/charting_library/static/images/tvcolorpicker-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/tvcolorpicker-check.png -------------------------------------------------------------------------------- /static/charting_library/static/images/tvcolorpicker-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/tvcolorpicker-sprite.png -------------------------------------------------------------------------------- /static/charting_library/static/images/warning-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aphtoken/aph-wallet-gui/269553b69a78c4570a1fd1d73ef5220f9fb9a4b6/static/charting_library/static/images/warning-icon.png -------------------------------------------------------------------------------- /static/charting_library/static/localization/translations/widgets-copyrights.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /static/charting_library/static/localization/translations/widgets-copyrights.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "default": "by {0}" 3 | } 4 | -------------------------------------------------------------------------------- /static/charting_library/static/styles.css: -------------------------------------------------------------------------------- 1 | .chart-page { 2 | background: rgba(255, 255, 255, .30); 3 | } 4 | 5 | .bottom-widgetbar-content.backtesting .button, 6 | .header-chart-panel .button, 7 | .hotlist-controls .button, 8 | .symbol-edit-widget .button, 9 | .favored-list-container span, 10 | .drawingToolbar-2CoOuCv8- { 11 | background: rgba(255, 255, 255, .30); 12 | } 13 | 14 | 15 | .Night .bottom-widgetbar-content.backtesting .button, 16 | .Night .header-chart-panel .button, 17 | .Night .hotlist-controls .button, 18 | .Night .symbol-edit-widget .button, 19 | .Night .favored-list-container span, 20 | .Night .drawingToolbar-2CoOuCv8- { 21 | color: #ffffff; 22 | } 23 | 24 | .Night .bottom-widgetbar-content.backtesting .button path, 25 | .Night .header-chart-panel .button path, 26 | .Night .hotlist-controls .button path, 27 | .Night .symbol-edit-widget .button path, 28 | .Night .favored-list-container span path, 29 | .Night .drawingToolbar-2CoOuCv8- path { 30 | fill: #ffffff; 31 | } 32 | -------------------------------------------------------------------------------- /static/charting_library/static/tv-chart.7580da73a91e1354cb09.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "assert": true, 7 | "expect": true, 8 | "should": true, 9 | "__static": true 10 | }, 11 | "rules": { 12 | "func-names": 0, 13 | "prefer-arrow-callback": 0 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/e2e/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // Set BABEL_ENV to use proper env config 4 | process.env.BABEL_ENV = 'test' 5 | 6 | // Enable use of ES6+ on required files 7 | require('babel-register')({ 8 | ignore: /node_modules/ 9 | }) 10 | 11 | // Attach Chai APIs to global scope 12 | const { expect, should, assert } = require('dirty-chai'); 13 | global.expect = expect 14 | global.should = should 15 | global.assert = assert 16 | global.sinon = require('sinon') 17 | 18 | // Require all JS files in `./specs` for Mocha to consume 19 | require('require-dir')('./specs') 20 | -------------------------------------------------------------------------------- /test/e2e/specs/Launch.spec.js: -------------------------------------------------------------------------------- 1 | import utils from '../utils'; 2 | 3 | describe('Launch', function () { 4 | beforeEach(utils.beforeEach); 5 | afterEach(utils.afterEach); 6 | 7 | it('shows the proper application title', function () { 8 | return this.app.client.getTitle() 9 | .then((title) => { 10 | expect(title).to.equal('Aphelion Desktop Wallet'); 11 | }); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/e2e/utils.js: -------------------------------------------------------------------------------- 1 | import electron from 'electron' 2 | import { Application } from 'spectron' 3 | 4 | export default { 5 | afterEach () { 6 | this.timeout(10000) 7 | 8 | if (this.app && this.app.isRunning()) { 9 | return this.app.stop() 10 | } 11 | }, 12 | beforeEach () { 13 | this.timeout(10000) 14 | this.app = new Application({ 15 | path: electron, 16 | args: ['dist/electron/main.js'], 17 | startTimeout: 10000, 18 | waitTimeout: 10000 19 | }) 20 | 21 | return this.app.start() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | Vue.config.devtools = false 3 | Vue.config.productionTip = false 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('../../src/renderer/services', true) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | const merge = require('webpack-merge') 5 | const webpack = require('webpack') 6 | 7 | const baseConfig = require('../../.electron-vue/webpack.renderer.config') 8 | const projectRoot = path.resolve(__dirname, '../../src/renderer') 9 | 10 | // Set BABEL_ENV to use proper preset config 11 | process.env.BABEL_ENV = 'test' 12 | 13 | let webpackConfig = merge(baseConfig, { 14 | devtool: '#inline-source-map', 15 | plugins: [ 16 | new webpack.DefinePlugin({ 17 | 'process.env.NODE_ENV': '"testing"' 18 | }) 19 | ] 20 | }) 21 | 22 | // don't treat dependencies as externals 23 | delete webpackConfig.entry 24 | delete webpackConfig.externals 25 | delete webpackConfig.output.libraryTarget 26 | 27 | // apply vue option to apply isparta-loader on js 28 | webpackConfig.module.rules 29 | .find(rule => rule.use.loader === 'vue-loader').use.options.loaders.js = 'babel-loader' 30 | 31 | module.exports = config => { 32 | config.set({ 33 | browsers: ['visibleElectron'], 34 | captureConsole: { 35 | client: { 36 | captureConsole: true, 37 | mocha: { 38 | bail: true 39 | } 40 | } 41 | }, 42 | client: { 43 | useIframe: false 44 | }, 45 | coverageReporter: { 46 | dir: './coverage', 47 | reporters: [ 48 | { type: 'lcov', subdir: '.' }, 49 | { type: 'text-summary' } 50 | ] 51 | }, 52 | customLaunchers: { 53 | 'visibleElectron': { 54 | base: 'Electron' 55 | } 56 | }, 57 | frameworks: ['mocha', 'dirty-chai', 'chai-sinon'], 58 | files: ['./index.js'], 59 | preprocessors: { 60 | './index.js': ['webpack', 'sourcemap'] 61 | }, 62 | reporters: ['spec', 'coverage'], 63 | singleRun: true, 64 | webpack: webpackConfig, 65 | webpackMiddleware: { 66 | noInfo: true 67 | }, 68 | }) 69 | } 70 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/Holding.spec.js: -------------------------------------------------------------------------------- 1 | import Holding from '@/components/Holding'; 2 | import utils from './utils'; 3 | 4 | let wrapper; 5 | 6 | const opts = { 7 | propsData: { 8 | holding: { 9 | asset: 'Aphelion', 10 | balance: 100, 11 | change24hrPercent: 2, 12 | contractBalance: 10, 13 | name: 'Aphelion', 14 | openOrdersBalance: 15, 15 | symbol: 'APH', 16 | }, 17 | }, 18 | stubs: { 19 | 'aph-token-icon': require('@/components/TokenIcon.vue').default, 20 | }, 21 | }; 22 | 23 | describe('Holding.vue', () => { 24 | context('positive 24 hour change', () => { 25 | it('should render with correctly formatted data', () => { 26 | wrapper = utils.mount(Holding, opts); 27 | 28 | expect(wrapper.find('.name').text()).contains('Aphelion'); 29 | expect(wrapper.find('.currency').text()).contains('APH'); 30 | expect(wrapper.find('.formatted').text()).contains('100'); 31 | expect(wrapper.find('.currency').text()).contains('APH'); 32 | expect(wrapper.find('.increase').text()).contains('2'); 33 | }); 34 | }); 35 | 36 | context('negative 24 hour change', () => { 37 | it('should render with correctly formatted data', () => { 38 | wrapper = utils.mount(Holding, _.set(opts, 'propsData.holding.change24hrPercent', -3)); 39 | 40 | expect(wrapper.find('.name').text()).contains('Aphelion'); 41 | expect(wrapper.find('.currency').text()).contains('APH'); 42 | expect(wrapper.find('.formatted').text()).contains('100'); 43 | expect(wrapper.find('.currency').text()).contains('APH'); 44 | expect(wrapper.find('.decrease').text()).contains('3'); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/PortfolioHeader.spec.js: -------------------------------------------------------------------------------- 1 | import sinon from 'sinon'; 2 | 3 | import PortfolioHeader from '@/components/PortfolioHeader'; 4 | import utils from './utils'; 5 | 6 | let push; 7 | let wrapper; 8 | 9 | describe('PortfolioHeader.vue', () => { 10 | beforeEach(() => { 11 | const customState = { 12 | currentNetwork: { 13 | net: 'MainNet', 14 | }, 15 | portfolio: { 16 | balance: 200, 17 | changePercent: 50, 18 | changeValue: 100, 19 | }, 20 | }; 21 | 22 | const opts = { 23 | stubs: { 24 | 'address-modal': '
', 25 | 'aph-icon': '
', 26 | zoom: '
', 27 | }, 28 | }; 29 | 30 | wrapper = utils.mount(PortfolioHeader, opts, customState); 31 | }); 32 | 33 | it('should render with correctly formatted data', () => { 34 | expect(wrapper.find('h1.underlined').text()).contains('My Portfolio'); 35 | expect(wrapper.find('.balance .amount').text()).contains('$200.00'); 36 | expect(wrapper.find('.change .amount').text()).contains('$100.00'); 37 | }); 38 | 39 | context('when a user clicks the receive button', () => { 40 | it('should show the address modal component', () => { 41 | wrapper.vm.$services.wallets.setCurrentWallet({ address: 'address' }); 42 | wrapper.find('.receive-btn').trigger('click'); 43 | 44 | expect(wrapper.contains('#aph-address-modal')).to.be.true(); 45 | }); 46 | }); 47 | 48 | context('when a user clicks the send button', () => { 49 | it('should update the route', () => { 50 | push = wrapper.vm.$router.push = sinon.spy(); 51 | wrapper.find('.send-btn').trigger('click'); 52 | 53 | expect(push).to.have.been.calledWith('/authenticated/dashboard/send'); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/TransactionsSidebar.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import sinon from 'sinon'; 3 | 4 | import TransactionsSidebar from '@/components/TransactionsSidebar'; 5 | import utils from './utils'; 6 | 7 | const RECENT_TRANSACTIONS = [ 8 | { 9 | from: 'from', 10 | to: 'to', 11 | value: 1, 12 | }, 13 | { 14 | from: 'from', 15 | to: 'to', 16 | value: -1, 17 | }, 18 | ]; 19 | const COMPUTED_TRANSACTIONS = [ 20 | { 21 | address: 'from', 22 | from: 'from', 23 | to: 'to', 24 | value: 1, 25 | }, 26 | { 27 | address: 'to', 28 | from: 'from', 29 | to: 'to', 30 | value: -1, 31 | }, 32 | ]; 33 | 34 | let loadTransactions; 35 | let wrapper; 36 | 37 | describe('TransactionsSidebar.vue', () => { 38 | beforeEach(() => { 39 | loadTransactions = sinon.spy(); 40 | Vue.prototype.$constants.intervals.TRANSACTIONS_POLLING = 5; 41 | 42 | const customState = { 43 | recentTransactions: RECENT_TRANSACTIONS, 44 | }; 45 | 46 | const opts = { 47 | methods: { loadTransactions }, 48 | stubs: { 49 | 'aph-icon': require('@/components/Icon.vue').default, 50 | 'aph-simple-transactions': '
', 51 | }, 52 | }; 53 | 54 | wrapper = utils.mount(TransactionsSidebar, opts, customState); 55 | }); 56 | 57 | context('always', () => { 58 | beforeEach((done) => { 59 | setTimeout(done, 5); 60 | }); 61 | 62 | it('should render with correctly formatted data', () => { 63 | expect(wrapper.find('h1.underlined').text()).contains('Recent Transactions'); 64 | expect(wrapper.contains('#transactions-sidebar')).to.be.true(); 65 | }); 66 | 67 | it('should properly compute computed properties', () => { 68 | expect(wrapper.vm.transactions).to.eql(COMPUTED_TRANSACTIONS); 69 | }); 70 | 71 | it('should fetch transactions', () => { 72 | expect(loadTransactions).to.have.been.calledThrice(); 73 | }); 74 | }); 75 | 76 | context('the user clicks the toggle to open', () => { 77 | it('should show the correct icon', () => { 78 | wrapper.find('.toggle').trigger('click'); 79 | 80 | expect(wrapper.contains('.icon.double-arrow-right')).to.be.true(); 81 | }); 82 | }); 83 | 84 | context('the user clicks the toggle to close', () => { 85 | it('should show the correct icon', () => { 86 | wrapper.setData({ open: true }); 87 | wrapper.find('.toggle').trigger('click'); 88 | 89 | expect(wrapper.contains('.icon.history')).to.be.true(); 90 | }); 91 | }); 92 | 93 | context('the component is destroyed', () => { 94 | it('should clear the interval', () => { 95 | window.clearInterval = sinon.spy(); 96 | wrapper.destroy(); 97 | 98 | expect(window.clearInterval).to.have.been.calledOnce(); 99 | }); 100 | }); 101 | }); 102 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/charts/SimpleDonut.spec.js: -------------------------------------------------------------------------------- 1 | import SimpleDonut from '@/components/charts/SimpleDonut'; 2 | import utils from './../utils'; 3 | 4 | describe('SimpleDonut.vue', () => { 5 | context('the percentage is positive', () => { 6 | it('should render with correctly formatted data', () => { 7 | const wrapper = utils.mount(SimpleDonut, { 8 | propsData: { 9 | percent: 12.3, 10 | }, 11 | }); 12 | 13 | expect(wrapper.find('.label').text()).contains('24 Hour'); 14 | expect(wrapper.find('.percent').text()).contains('12.3%'); 15 | }); 16 | }); 17 | 18 | context('the percentage is negative', () => { 19 | it('should render with correctly formatted data', () => { 20 | const wrapper = utils.mount(SimpleDonut, { 21 | propsData: { 22 | label: 'NEGATIVE 24 Hour', 23 | percent: 12.3, 24 | }, 25 | }); 26 | 27 | expect(wrapper.find('.label').text()).contains('NEGATIVE 24 Hour'); 28 | expect(wrapper.find('.percent').text()).contains('12.3%'); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/login/CreateWallet.spec.js: -------------------------------------------------------------------------------- 1 | import CreateWallet from '@/components/login/CreateWallet'; 2 | import utils from '../utils'; 3 | 4 | let wrapper; 5 | 6 | describe('CreateWallet.vue', () => { 7 | beforeEach(() => { 8 | wrapper = utils.shallow(CreateWallet); 9 | }); 10 | 11 | it('should render', () => { 12 | expect(wrapper.contains('#login--create-wallet')).to.be.true(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/login/EncryptedKey.spec.js: -------------------------------------------------------------------------------- 1 | import EncryptedKey from '@/components/login/EncryptedKey'; 2 | import utils from '../utils'; 3 | 4 | let wrapper; 5 | 6 | describe('EncryptedKey.vue', () => { 7 | beforeEach(() => { 8 | wrapper = utils.shallow(EncryptedKey); 9 | }); 10 | 11 | it('should render', () => { 12 | expect(wrapper.contains('#login--encrypted-key')).to.be.true(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/login/Landing.spec.js: -------------------------------------------------------------------------------- 1 | import Landing from '@/components/login/Landing'; 2 | import utils from '../utils'; 3 | 4 | let wrapper; 5 | 6 | describe('Landing.vue', () => { 7 | beforeEach(() => { 8 | wrapper = utils.shallow(Landing); 9 | }); 10 | 11 | it('should render', () => { 12 | expect(wrapper.contains('#login--landing')).to.be.true(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/login/SavedWallet.spec.js: -------------------------------------------------------------------------------- 1 | import SavedWallet from '@/components/login/SavedWallet'; 2 | import utils from '../utils'; 3 | 4 | let wrapper; 5 | 6 | describe('SavedWallet.vue', () => { 7 | beforeEach(() => { 8 | wrapper = utils.shallow(SavedWallet); 9 | }); 10 | 11 | it('should render', () => { 12 | expect(wrapper.contains('#login--saved-wallet')).to.be.true(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/unit/specs/renderer/components/utils.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueI18n from 'vue-i18n'; 3 | import Vuex from 'vuex'; 4 | import _ from 'lodash'; 5 | import { mount, shallowMount } from '@vue/test-utils'; 6 | 7 | // Initial vue libraries 8 | import '@/decorators'; 9 | import * as mixins from '@/mixins'; 10 | import router from '@/router'; 11 | import { actions, getters, mutations, state } from '@/store'; 12 | import { messages } from '@/constants'; 13 | 14 | Vue.use(VueI18n); 15 | 16 | _.each(mixins, (mixin) => { 17 | Vue.mixin(mixin); 18 | }); 19 | 20 | // Register global components. 21 | Vue.component('aph-copy-text', require('@/components/CopyText.vue')); 22 | Vue.component('aph-date-picker', require('@/components/DatePicker.vue')); 23 | Vue.component('aph-dex-input', require('@/components/DexInput.vue')); 24 | Vue.component('aph-form', require('@/components/Form.vue')); 25 | Vue.component('aph-holding', require('@/components/Holding.vue')); 26 | Vue.component('aph-icon', require('@/components/Icon.vue')); 27 | Vue.component('aph-input', require('@/components/Input.vue')); 28 | Vue.component('aph-select', require('@/components/Select.vue')); 29 | Vue.component('aph-simple-transactions', require('@/components/SimpleTransactions.vue')); 30 | Vue.component('aph-timestamp-from-now', require('@/components/TimestampFromNow.vue')); 31 | Vue.component('aph-token-icon', require('@/components/TokenIcon.vue')); 32 | Vue.component('aph-spinner-wrapper', require('@/components/SpinnerWrapper.vue')); 33 | 34 | const getI18n = () => { 35 | return new VueI18n({ 36 | fallbackLocale: 'en', 37 | locale: 'en', 38 | messages: { 39 | en: messages.en, 40 | }, 41 | }); 42 | }; 43 | 44 | const getDefaultOpts = (customState) => { 45 | const store = new Vuex.Store({ 46 | actions, 47 | getters, 48 | mutations, 49 | state: _.assign(state, customState), 50 | }); 51 | 52 | return { i18n: getI18n(), router, store }; 53 | }; 54 | 55 | export default { 56 | mount(component, opts, customState) { 57 | return mount(component, _.merge(getDefaultOpts(customState), opts)); 58 | }, 59 | 60 | shallow(component, opts, customState) { 61 | return shallowMount(component, _.merge(getDefaultOpts(customState), opts)); 62 | }, 63 | }; 64 | --------------------------------------------------------------------------------