From 7677d2650bbc3e6fb1dc5c879b713383543ed2bc Mon Sep 17 00:00:00 2001 From: Aleksey Popov Date: Wed, 24 May 2017 23:07:36 +0300 Subject: [PATCH 1/5] Add event handlers and some electron improvements --- .eslintrc.json | 3 ++- app/main.js | 6 ++++++ src/index.pug | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index de6256109..273f715d8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,7 +5,8 @@ ], "globals": { "angular": true, - "app": true + "app": true, + "electron": true }, "env": { "browser": true, diff --git a/app/main.js b/app/main.js index 1eb5e7285..76a4de413 100644 --- a/app/main.js +++ b/app/main.js @@ -12,7 +12,13 @@ function createWindow() { width: width > 2000 ? Math.floor(width * 0.5) : width - 250, height: height > 1000 ? Math.floor(height * 0.7) : height - 150, center: true, + webPreferences: { + // Avoid app throttling when Electron is in background + backgroundThrottling: false, + }, }); + win.on('blur', () => win.webContents.send('blur')); + win.on('focus', () => win.webContents.send('focus')); const template = [ { diff --git a/src/index.pug b/src/index.pug index bfc84c9bf..cdc07542b 100644 --- a/src/index.pug +++ b/src/index.pug @@ -7,6 +7,10 @@ html body { background-color: #eee !important; } + script. + if (window.require) { + var electron = window.require('electron'); + } body div.body-wrapper md-content(id="main", flex='100', flex-gt-sm='80', flex-offset-gt-sm='10') From e944e7b0712f8b9877d4bf565e6920451721337e Mon Sep 17 00:00:00 2001 From: Aleksey Popov Date: Wed, 24 May 2017 23:08:47 +0300 Subject: [PATCH 2/5] Add Notify factory --- src/components/main/main.js | 7 +++- src/liskNano.js | 1 + src/services/notify.js | 73 +++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/services/notify.js diff --git a/src/components/main/main.js b/src/components/main/main.js index 423706521..feb1c4480 100644 --- a/src/components/main/main.js +++ b/src/components/main/main.js @@ -17,7 +17,7 @@ app.component('main', { */ controller: class main { constructor($scope, $rootScope, $timeout, $q, $state, Peers, - dialog, SendModal, Account, AccountApi) { + dialog, SendModal, Account, AccountApi, Notify) { this.$scope = $scope; this.$rootScope = $rootScope; this.$timeout = $timeout; @@ -28,6 +28,7 @@ app.component('main', { this.$state = $state; this.account = Account; this.accountApi = AccountApi; + this.notify = Notify.init(); this.activeTab = this.init(); } @@ -110,6 +111,10 @@ app.component('main', { delete res.publicKey; } + this.notify.about( + 'deposite', + res.balance - this.account.get().balance, + ); this.account.set(res); }) .catch((res) => { diff --git a/src/liskNano.js b/src/liskNano.js index 821a9a29c..e64c99cb8 100644 --- a/src/liskNano.js +++ b/src/liskNano.js @@ -24,6 +24,7 @@ import './components/delegateRegistration/delegateRegistration'; import './services/api/peers'; import './services/lsk'; +import './services/notify'; import './services/dialog'; import './services/passphrase'; import './services/signVerify'; diff --git a/src/services/notify.js b/src/services/notify.js new file mode 100644 index 000000000..a4dafa968 --- /dev/null +++ b/src/services/notify.js @@ -0,0 +1,73 @@ +/** + * @description This factory provides methods to call Notification + * + * @module app + * @submodule Notify + */ +app.factory('Notify', ($window, lsk) => { + /** + * The Notify factory constructor class + * @class Notify + * @constructor + */ + class Notify { + constructor() { + this.isFocused = true; + } + + /** + * Initialize event listeners + * + * @returns {this} + * @method init + * @memberof Notify + */ + init() { + const { electron } = $window; + if (electron) { + electron.ipcRenderer.on('blur', () => this.isFocused = false); + electron.ipcRenderer.on('focus', () => this.isFocused = true); + } + return this; + } + + /** + * Routing to specific Notification creator based on type param + * @param {string} type + * @param {any} data + * + * @method about + * @public + * @memberof Notify + */ + about(type, data) { + if (this.isFocused) return; + switch (type) { + case 'deposite': + this.__deposite(data); + break; + default: break; + } + } + + /** + * Creating notification about deposit + * + * @param {number} amount + * @private + * @memberof Notify + */ + __deposite(amount) { // eslint-disable-line + if (amount > 0) { + new $window.Notification( // eslint-disable-line + 'LSK received', + { + body: `You've received ${lsk.normalize(amount)} LSK.`, + }, + ); + } + } + } + + return new Notify(); +}); From 19ac8f1d47281561da7d25f29bcafd7269f12bc6 Mon Sep 17 00:00:00 2001 From: Aleksey Popov Date: Wed, 24 May 2017 23:09:09 +0300 Subject: [PATCH 3/5] Add tests for Notify factory --- test/services/notify.spec.js | 57 ++++++++++++++++++++++++++++++++++++ test/test.js | 1 + 2 files changed, 58 insertions(+) create mode 100644 test/services/notify.spec.js diff --git a/test/services/notify.spec.js b/test/services/notify.spec.js new file mode 100644 index 000000000..64baeb325 --- /dev/null +++ b/test/services/notify.spec.js @@ -0,0 +1,57 @@ +const chai = require('chai'); +const sinon = require('sinon'); +const sinonChai = require('sinon-chai'); + +const expect = chai.expect; +chai.use(sinonChai); + +describe('Factory: Notify', () => { + let lsk; + let $window; + let notify; + + beforeEach(angular.mock.module('app')); + + beforeEach(inject((_Notify_, _lsk_, _$window_) => { + lsk = _lsk_; + $window = _$window_; + notify = _Notify_.init(); + })); + + describe('about(data)', () => { + const amount = 100000000; + const mockNotification = sinon.spy(); + + it('should call this.__deposite', () => { + const spy = sinon.spy(notify, '__deposite'); + notify.isFocused = false; + notify.about('deposite', amount); + expect(spy).to.have.been.calledWith(amount); + }); + + it('should call $window.Notification', () => { + $window.Notification = mockNotification; + const msg = `You've received ${lsk.normalize(amount)} LSK.`; + + notify.isFocused = false; + notify.about('deposite', amount); + expect(mockNotification).to.have.been.calledWith( + 'LSK received', { body: msg }, + ); + mockNotification.reset(); + }); + + it('should not call $window.Notification if app is focused', () => { + notify.about('deposite', amount); + expect(mockNotification).to.have.been.not.calledWith(); + mockNotification.reset(); + }); + + it('should not call $window.Notification if amount equal 0 or negative', () => { + notify.isFocused = false; + notify.about('deposite', 0); + notify.about('deposite', -1); + expect(mockNotification.callCount).to.have.been.equal(0); + }); + }); +}); diff --git a/test/test.js b/test/test.js index da5d967d8..8d0c372a1 100644 --- a/test/test.js +++ b/test/test.js @@ -19,6 +19,7 @@ require('./components/delegateRegistration/delegateRegistration.spec.js'); require('./services/passphrase.spec'); require('./services/signVerify.spec'); require('./services/lsk.spec'); +require('./services/notify.spec'); require('./services/api/peers.spec'); require('./services/api/delegateApi.spec'); require('./services/api/forgingApi.spec'); From 2c8f79e0921490089c10849cbbab5a2ac32f7780 Mon Sep 17 00:00:00 2001 From: Aleksey Popov Date: Tue, 30 May 2017 14:43:54 +0300 Subject: [PATCH 4/5] Change sync interval when app is not in focus --- src/services/sync.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/services/sync.js b/src/services/sync.js index 0797c5ae2..818ed0f9e 100644 --- a/src/services/sync.js +++ b/src/services/sync.js @@ -1,6 +1,11 @@ +const intervals = { + activeApp: 10000, + inactiveApp: 60000, +}; + app.factory('Sync', ($rootScope, $window) => { const config = { - updateInterval: 10000, + updateInterval: intervals.activeApp, freeze: false, }; let lastTick = new Date(); @@ -33,6 +38,19 @@ app.factory('Sync', ($rootScope, $window) => { $window.requestAnimationFrame(step); } }; + + const toggleSyncTimer = (inFocus) => { + config.updateInterval = (inFocus) ? + intervals.activeApp : + intervals.inactiveApp; + }; + + const initIntervalToggler = () => { + const { electron } = $window; + electron.ipcRenderer.on('blur', () => toggleSyncTimer(false)); + electron.ipcRenderer.on('focus', () => toggleSyncTimer(true)); + }; + /** * Starts the first frame by calling requestAnimationFrame. * This will be @@ -41,6 +59,10 @@ app.factory('Sync', ($rootScope, $window) => { if (!running) { $window.requestAnimationFrame(step); } + + if ($window.electron) { + initIntervalToggler(); + } }; /** From 7612b0ab4682b472b8faa0b0647ea70ebdd6cb23 Mon Sep 17 00:00:00 2001 From: Aleksey Popov Date: Wed, 31 May 2017 17:11:43 +0300 Subject: [PATCH 5/5] - Rename Notify -> Notification - Fix typo - Define `PRODUCTION` flag - Load `ipcRenderer` to window object through the `preload` option --- .eslintrc | 3 +- app/ipc.js | 5 ++++ app/main.js | 3 ++ package.json | 2 +- src/components/main/main.js | 13 ++++---- src/index.pug | 4 --- src/liskNano.js | 2 +- src/services/{notify.js => notification.js} | 30 ++++++++----------- src/services/sync.js | 10 +++---- .../{notify.spec.js => notification.spec.js} | 23 +++++--------- test/test.js | 2 +- webpack.config.babel.js | 12 ++++++-- 12 files changed, 54 insertions(+), 55 deletions(-) create mode 100644 app/ipc.js rename src/services/{notify.js => notification.js} (60%) rename test/services/{notify.spec.js => notification.spec.js} (62%) diff --git a/.eslintrc b/.eslintrc index fecfd7d8b..604b87260 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,7 +6,8 @@ "globals": { "angular": true, "app": true, - "electron": true + "ipc": true, + "PRODUCTION": true }, "env": { "browser": true, diff --git a/app/ipc.js b/app/ipc.js new file mode 100644 index 000000000..b31218954 --- /dev/null +++ b/app/ipc.js @@ -0,0 +1,5 @@ +/** + * Add ipcRenderer to the window object + */ +const ipcRenderer = window.require('electron').ipcRenderer; +window.ipc = ipcRenderer; diff --git a/app/main.js b/app/main.js index 76a4de413..a0a5f7033 100644 --- a/app/main.js +++ b/app/main.js @@ -1,4 +1,5 @@ const electron = require('electron'); // eslint-disable-line import/no-extraneous-dependencies +const path = require('path'); const { app } = electron; const { BrowserWindow } = electron; @@ -15,6 +16,8 @@ function createWindow() { webPreferences: { // Avoid app throttling when Electron is in background backgroundThrottling: false, + // Specifies a script that will be loaded before other scripts run in the page. + preload: path.resolve(__dirname, 'ipc.js'), }, }); win.on('blur', () => win.webContents.send('blur')); diff --git a/package.json b/package.json index 886142a04..35c7c9627 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "bugs": "https://github.com/LiskHQ/lisk-nano/issues", "main": "main.js", "scripts": { - "build": "webpack --profile --progress --display-modules --display-exclude --display-chunks --display-cached --display-cached-assets", + "build": "export NODE_ENV=prod && webpack --profile --progress --display-modules --display-exclude --display-chunks --display-cached --display-cached-assets", "dev": "webpack-dev-server --host 0.0.0.0 --profile --progress", "e2e-test": "protractor protractor.conf.js", "test": "grunt eslint && export NODE_ENV=test && karma start", diff --git a/src/components/main/main.js b/src/components/main/main.js index feb1c4480..c3bbd3c1c 100644 --- a/src/components/main/main.js +++ b/src/components/main/main.js @@ -17,7 +17,7 @@ app.component('main', { */ controller: class main { constructor($scope, $rootScope, $timeout, $q, $state, Peers, - dialog, SendModal, Account, AccountApi, Notify) { + dialog, SendModal, Account, AccountApi, Notification) { this.$scope = $scope; this.$rootScope = $rootScope; this.$timeout = $timeout; @@ -28,7 +28,7 @@ app.component('main', { this.$state = $state; this.account = Account; this.accountApi = AccountApi; - this.notify = Notify.init(); + this.notify = Notification.init(); this.activeTab = this.init(); } @@ -111,10 +111,11 @@ app.component('main', { delete res.publicKey; } - this.notify.about( - 'deposite', - res.balance - this.account.get().balance, - ); + if (res.balance > this.account.get().balance) { + const amount = res.balance - this.account.get().balance; + this.notify.about('deposit', amount); + } + this.account.set(res); }) .catch((res) => { diff --git a/src/index.pug b/src/index.pug index cdc07542b..bfc84c9bf 100644 --- a/src/index.pug +++ b/src/index.pug @@ -7,10 +7,6 @@ html body { background-color: #eee !important; } - script. - if (window.require) { - var electron = window.require('electron'); - } body div.body-wrapper md-content(id="main", flex='100', flex-gt-sm='80', flex-offset-gt-sm='10') diff --git a/src/liskNano.js b/src/liskNano.js index e64c99cb8..5ac73bd88 100644 --- a/src/liskNano.js +++ b/src/liskNano.js @@ -24,7 +24,7 @@ import './components/delegateRegistration/delegateRegistration'; import './services/api/peers'; import './services/lsk'; -import './services/notify'; +import './services/notification'; import './services/dialog'; import './services/passphrase'; import './services/signVerify'; diff --git a/src/services/notify.js b/src/services/notification.js similarity index 60% rename from src/services/notify.js rename to src/services/notification.js index a4dafa968..0cd9e00ca 100644 --- a/src/services/notify.js +++ b/src/services/notification.js @@ -4,13 +4,13 @@ * @module app * @submodule Notify */ -app.factory('Notify', ($window, lsk) => { +app.factory('Notification', ($window, lsk) => { /** * The Notify factory constructor class * @class Notify * @constructor */ - class Notify { + class Notification { constructor() { this.isFocused = true; } @@ -23,10 +23,10 @@ app.factory('Notify', ($window, lsk) => { * @memberof Notify */ init() { - const { electron } = $window; - if (electron) { - electron.ipcRenderer.on('blur', () => this.isFocused = false); - electron.ipcRenderer.on('focus', () => this.isFocused = true); + if (PRODUCTION) { + const { ipc } = $window; + ipc.on('blur', () => this.isFocused = false); + ipc.on('focus', () => this.isFocused = true); } return this; } @@ -43,8 +43,8 @@ app.factory('Notify', ($window, lsk) => { about(type, data) { if (this.isFocused) return; switch (type) { - case 'deposite': - this.__deposite(data); + case 'deposit': + this._deposit(data); break; default: break; } @@ -57,17 +57,11 @@ app.factory('Notify', ($window, lsk) => { * @private * @memberof Notify */ - __deposite(amount) { // eslint-disable-line - if (amount > 0) { - new $window.Notification( // eslint-disable-line - 'LSK received', - { - body: `You've received ${lsk.normalize(amount)} LSK.`, - }, - ); - } + _deposit(amount) { // eslint-disable-line + const body = `You've received ${lsk.normalize(amount)} LSK.`; + new $window.Notification('LSK received', { body }); // eslint-disable-line } } - return new Notify(); + return new Notification(); }); diff --git a/src/services/sync.js b/src/services/sync.js index 818ed0f9e..72cf5f07e 100644 --- a/src/services/sync.js +++ b/src/services/sync.js @@ -46,9 +46,9 @@ app.factory('Sync', ($rootScope, $window) => { }; const initIntervalToggler = () => { - const { electron } = $window; - electron.ipcRenderer.on('blur', () => toggleSyncTimer(false)); - electron.ipcRenderer.on('focus', () => toggleSyncTimer(true)); + const { ipc } = $window; + ipc.on('blur', () => toggleSyncTimer(false)); + ipc.on('focus', () => toggleSyncTimer(true)); }; /** @@ -59,8 +59,7 @@ app.factory('Sync', ($rootScope, $window) => { if (!running) { $window.requestAnimationFrame(step); } - - if ($window.electron) { + if (PRODUCTION) { initIntervalToggler(); } }; @@ -72,7 +71,6 @@ app.factory('Sync', ($rootScope, $window) => { config.freeze = false; }; - init(); return { init, config, end, }; diff --git a/test/services/notify.spec.js b/test/services/notification.spec.js similarity index 62% rename from test/services/notify.spec.js rename to test/services/notification.spec.js index 64baeb325..ef3ea624d 100644 --- a/test/services/notify.spec.js +++ b/test/services/notification.spec.js @@ -5,27 +5,27 @@ const sinonChai = require('sinon-chai'); const expect = chai.expect; chai.use(sinonChai); -describe('Factory: Notify', () => { +describe('Factory: Notification', () => { let lsk; let $window; let notify; beforeEach(angular.mock.module('app')); - beforeEach(inject((_Notify_, _lsk_, _$window_) => { + beforeEach(inject((_Notification_, _lsk_, _$window_) => { lsk = _lsk_; $window = _$window_; - notify = _Notify_.init(); + notify = _Notification_.init(); })); describe('about(data)', () => { const amount = 100000000; const mockNotification = sinon.spy(); - it('should call this.__deposite', () => { - const spy = sinon.spy(notify, '__deposite'); + it('should call this._deposit', () => { + const spy = sinon.spy(notify, '_deposit'); notify.isFocused = false; - notify.about('deposite', amount); + notify.about('deposit', amount); expect(spy).to.have.been.calledWith(amount); }); @@ -34,7 +34,7 @@ describe('Factory: Notify', () => { const msg = `You've received ${lsk.normalize(amount)} LSK.`; notify.isFocused = false; - notify.about('deposite', amount); + notify.about('deposit', amount); expect(mockNotification).to.have.been.calledWith( 'LSK received', { body: msg }, ); @@ -42,16 +42,9 @@ describe('Factory: Notify', () => { }); it('should not call $window.Notification if app is focused', () => { - notify.about('deposite', amount); + notify.about('deposit', amount); expect(mockNotification).to.have.been.not.calledWith(); mockNotification.reset(); }); - - it('should not call $window.Notification if amount equal 0 or negative', () => { - notify.isFocused = false; - notify.about('deposite', 0); - notify.about('deposite', -1); - expect(mockNotification.callCount).to.have.been.equal(0); - }); }); }); diff --git a/test/test.js b/test/test.js index 8d0c372a1..bc4061761 100644 --- a/test/test.js +++ b/test/test.js @@ -19,7 +19,7 @@ require('./components/delegateRegistration/delegateRegistration.spec.js'); require('./services/passphrase.spec'); require('./services/signVerify.spec'); require('./services/lsk.spec'); -require('./services/notify.spec'); +require('./services/notification.spec'); require('./services/api/peers.spec'); require('./services/api/delegateApi.spec'); require('./services/api/forgingApi.spec'); diff --git a/webpack.config.babel.js b/webpack.config.babel.js index 4e6cc2240..a036a326e 100644 --- a/webpack.config.babel.js +++ b/webpack.config.babel.js @@ -169,6 +169,14 @@ const provide = () => ({ ], }); +const define = () => ({ + plugins: [ + new webpack.DefinePlugin({ + PRODUCTION: JSON.stringify(nodeEnvironment === 'prod'), + }), + ], +}); + const bundleAnalyzer = () => ({ plugins: [ new BundleAnalyzerPlugin({ @@ -182,10 +190,10 @@ let config; switch (process.env.npm_lifecycle_event) { case 'build': - config = merge(common, clean(path.join(PATHS.build, 'dist')), html(), provide(), eslint(), babel(), pug(), less(), css(), json(), png(), fonts(), bundleAnalyzer()); + config = merge(common, clean(path.join(PATHS.build, 'dist')), html(), provide(), define(), eslint(), babel(), pug(), less(), css(), json(), png(), fonts(), bundleAnalyzer()); break; default: - config = merge(common, devServer(), { devtool: 'eval-source-map' }, html(), provide(), eslint(), babel(), pug(), less(), css(), json(), png(), fonts()); + config = merge(common, devServer(), { devtool: 'eval-source-map' }, html(), provide(), define(), eslint(), babel(), pug(), less(), css(), json(), png(), fonts()); break; }