refactor(GUI): make OSWindowProgress a simple CommonJS module (#1253)

There is no need to tie this module to Angular by using an Angular
service.

Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
Juan Cruz Viotti 2017-04-13 14:38:22 -04:00 committed by GitHub
parent 55021376b5
commit 64c8eb594b
9 changed files with 293 additions and 136 deletions

View File

@ -32,6 +32,7 @@ const EXIT_CODES = require('../shared/exit-codes');
const messages = require('../shared/messages');
const packageJSON = require('../../package.json');
const flashState = require('./models/flash-state');
const windowProgress = require('./os/window-progress');
const Store = require('./models/store');
@ -60,7 +61,6 @@ const app = angular.module('Etcher', [
require('./pages/settings/settings'),
// OS
require('./os/window-progress/window-progress'),
require('./os/open-external/open-external'),
require('./os/dropzone/dropzone'),
require('./os/dialog/dialog'),
@ -129,7 +129,7 @@ app.run((AnalyticsService, ErrorService, UpdateNotifierService, SelectionStateMo
});
app.run((AnalyticsService, OSWindowProgressService) => {
app.run((AnalyticsService) => {
Store.subscribe(() => {
const currentFlashState = flashState.getFlashState();
@ -150,7 +150,7 @@ app.run((AnalyticsService, OSWindowProgressService) => {
`(eta ${currentFlashState.eta}s)`
].join(' '));
OSWindowProgressService.set(currentFlashState.percentage);
windowProgress.set(currentFlashState.percentage);
});
});

View File

@ -0,0 +1,63 @@
/*
* Copyright 2016 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const electron = require('electron');
const utils = require('../../shared/utils');
/**
* @summary A reference to the current renderer Electron window
* @type {Object}
* @protected
*
* @description
* We expose this property to `this` for testability purposes.
*/
exports.currentWindow = electron.remote.getCurrentWindow();
/**
* @summary Set operating system window progress
* @function
* @public
*
* @description
* Show progress inline in operating system task bar
*
* @param {Number} percentage - percentage
*
* @example
* windowProgress.set(85);
*/
exports.set = (percentage) => {
exports.currentWindow.setProgressBar(utils.percentageToFloat(percentage));
};
/**
* @summary Clear the window progress bar
* @function
* @public
*
* @example
* windowProgress.clear();
*/
exports.clear = () => {
// Passing 0 or null/undefined doesn't work.
const ELECTRON_PROGRESS_BAR_RESET_VALUE = -1;
exports.currentWindow.setProgressBar(ELECTRON_PROGRESS_BAR_RESET_VALUE);
};

View File

@ -1,74 +0,0 @@
/*
* Copyright 2016 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const electron = require('electron');
const errors = require('../../../../shared/errors');
module.exports = function() {
/**
* @summary A reference to the current renderer Electron window
* @type {Object}
* @protected
*
* @description
* We expose this property to `this` for testability purposes.
*/
this.currentWindow = electron.remote.getCurrentWindow();
/**
* @summary Set operating system window progress
* @function
* @public
*
* @description
* Show progress inline in operating system task bar
*
* @param {Number} percentage - percentage
*
* @example
* OSWindowProgressService.set(85);
*/
this.set = (percentage) => {
const PERCENTAGE_MINIMUM = 0;
const PERCENTAGE_MAXIMUM = 100;
if (percentage > PERCENTAGE_MAXIMUM || percentage < PERCENTAGE_MINIMUM) {
throw errors.createError(`Invalid window progress percentage: ${percentage}`);
}
this.currentWindow.setProgressBar(percentage / PERCENTAGE_MAXIMUM);
};
/**
* @summary Clear the operating system window progress bar
* @function
* @public
*
* @example
* OSWindowProgressService.clear();
*/
this.clear = () => {
// Passing 0 or null/undefined doesn't work.
const ELECTRON_PROGRESS_BAR_RESET_VALUE = -1;
this.currentWindow.setProgressBar(ELECTRON_PROGRESS_BAR_RESET_VALUE);
};
};

View File

@ -1,32 +0,0 @@
/*
* Copyright 2016 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
/**
* The purpose of this module is to provide an easy way
* to interact with the operating system's window progress
* functionality, as described in Electron docs.
*
* @module Etcher.OS.WindowProgress
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.OS.WindowProgress';
const OSWindowProgress = angular.module(MODULE_NAME, []);
OSWindowProgress.service('OSWindowProgressService', require('./services/window-progress'));
module.exports = MODULE_NAME;

View File

@ -19,6 +19,7 @@
const messages = require('../../../../shared/messages');
const settings = require('../../../models/settings');
const flashState = require('../../../models/flash-state');
const windowProgress = require('../../../os/window-progress');
module.exports = function(
$state,
@ -27,8 +28,7 @@ module.exports = function(
AnalyticsService,
FlashErrorModalService,
ErrorService,
OSNotificationService,
OSWindowProgressService
OSNotificationService
) {
/**
@ -105,7 +105,7 @@ module.exports = function(
})
.finally(() => {
OSWindowProgressService.clear();
windowProgress.clear();
DriveScannerService.start();
});
};

View File

@ -39,7 +39,6 @@ const MainPage = angular.module(MODULE_NAME, [
require('../../components/flash-error-modal/flash-error-modal'),
require('../../components/progress-button/progress-button'),
require('../../os/window-progress/window-progress'),
require('../../os/notification/notification'),
require('../../os/dialog/dialog'),
require('../../os/open-external/open-external'),

78
lib/shared/utils.js Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright 2017 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const _ = require('lodash');
const errors = require('./errors');
/**
* @summary Minimum percentage value
* @constant
* @private
* @type {Number}
*/
const PERCENTAGE_MINIMUM = 0;
/**
* @summary Maximum percentage value
* @constant
* @private
* @type {Number}
*/
const PERCENTAGE_MAXIMUM = 100;
/**
* @summary Check if a percentage is valid
* @function
* @public
*
* @param {Number} percentage - percentage
* @returns {Boolean} whether the percentage is valid
*
* @example
* if (utils.isValidPercentage(85)) {
* console.log('The percentage is valid');
* }
*/
exports.isValidPercentage = (percentage) => {
return _.every([
_.isNumber(percentage),
percentage >= PERCENTAGE_MINIMUM,
percentage <= PERCENTAGE_MAXIMUM
]);
};
/**
* @summary Convert a percentage to a float
* @function
* @public
*
* @param {Number} percentage - percentage
* @returns {Number} float percentage
*
* @example
* const value = utils.percentageToFloat(50);
* console.log(value);
* > 0.5
*/
exports.percentageToFloat = (percentage) => {
if (!exports.isValidPercentage(percentage)) {
throw errors.createError(`Invalid percentage: ${percentage}`);
}
return percentage / PERCENTAGE_MAXIMUM;
};

View File

@ -17,29 +17,18 @@
'use strict';
const m = require('mochainon');
const angular = require('angular');
require('angular-mocks');
const windowProgress = require('../../../lib/gui/os/window-progress');
describe('Browser: OSWindowProgress', function() {
describe('Browser: WindowProgress', function() {
beforeEach(angular.mock.module(
require('../../../lib/gui/os/window-progress/window-progress')
));
describe('OSWindowProgressService', function() {
let OSWindowProgressService;
beforeEach(angular.mock.inject(function(_OSWindowProgressService_) {
OSWindowProgressService = _OSWindowProgressService_;
}));
describe('windowProgress', function() {
describe('given a stubbed current window', function() {
beforeEach(function() {
this.setProgressBarSpy = m.sinon.spy();
OSWindowProgressService.currentWindow = {
windowProgress.currentWindow = {
setProgressBar: this.setProgressBarSpy
};
});
@ -47,30 +36,30 @@ describe('Browser: OSWindowProgress', function() {
describe('.set()', function() {
it('should translate 0-100 percentages to 0-1 ranges', function() {
OSWindowProgressService.set(85);
windowProgress.set(85);
m.chai.expect(this.setProgressBarSpy).to.have.been.calledWith(0.85);
});
it('should set 0 given 0', function() {
OSWindowProgressService.set(0);
windowProgress.set(0);
m.chai.expect(this.setProgressBarSpy).to.have.been.calledWith(0);
});
it('should set 1 given 100', function() {
OSWindowProgressService.set(100);
windowProgress.set(100);
m.chai.expect(this.setProgressBarSpy).to.have.been.calledWith(1);
});
it('should throw if given a percentage higher than 100', function() {
m.chai.expect(function() {
OSWindowProgressService.set(101);
}).to.throw('Invalid window progress percentage: 101');
windowProgress.set(101);
}).to.throw('Invalid percentage: 101');
});
it('should throw if given a percentage less than 0', function() {
m.chai.expect(function() {
OSWindowProgressService.set(-1);
}).to.throw('Invalid window progress percentage: -1');
windowProgress.set(-1);
}).to.throw('Invalid percentage: -1');
});
});
@ -78,7 +67,7 @@ describe('Browser: OSWindowProgress', function() {
describe('.clear()', function() {
it('should set -1', function() {
OSWindowProgressService.clear();
windowProgress.clear();
m.chai.expect(this.setProgressBarSpy).to.have.been.calledWith(-1);
});

134
tests/shared/utils.spec.js Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright 2017 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const m = require('mochainon');
const utils = require('../../lib/shared/utils');
describe('Shared: Utils', function() {
describe('.isValidPercentage()', function() {
it('should return false if percentage is not a number', function() {
m.chai.expect(utils.isValidPercentage('50')).to.be.false;
});
it('should return false if percentage is null', function() {
m.chai.expect(utils.isValidPercentage(null)).to.be.false;
});
it('should return false if percentage is undefined', function() {
m.chai.expect(utils.isValidPercentage(undefined)).to.be.false;
});
it('should return false if percentage is an integer less than 0', function() {
m.chai.expect(utils.isValidPercentage(-1)).to.be.false;
});
it('should return false if percentage is a float less than 0', function() {
m.chai.expect(utils.isValidPercentage(-0.1)).to.be.false;
});
it('should return true if percentage is 0', function() {
m.chai.expect(utils.isValidPercentage(0)).to.be.true;
});
it('should return true if percentage is an integer greater than 0, but less than 100', function() {
m.chai.expect(utils.isValidPercentage(50)).to.be.true;
});
it('should return true if percentage is a float greater than 0, but less than 100', function() {
m.chai.expect(utils.isValidPercentage(49.55)).to.be.true;
});
it('should return true if percentage is 100', function() {
m.chai.expect(utils.isValidPercentage(100)).to.be.true;
});
it('should return false if percentage is an integer greater than 100', function() {
m.chai.expect(utils.isValidPercentage(101)).to.be.false;
});
it('should return false if percentage is a float greater than 100', function() {
m.chai.expect(utils.isValidPercentage(100.001)).to.be.false;
});
});
describe('.percentageToFloat()', function() {
it('should throw an error if given a string percentage', function() {
m.chai.expect(function() {
utils.percentageToFloat('50');
}).to.throw('Invalid percentage: 50');
});
it('should throw an error if given a null percentage', function() {
m.chai.expect(function() {
utils.percentageToFloat(null);
}).to.throw('Invalid percentage: null');
});
it('should throw an error if given an undefined percentage', function() {
m.chai.expect(function() {
utils.percentageToFloat(undefined);
}).to.throw('Invalid percentage: undefined');
});
it('should throw an error if given an integer percentage < 0', function() {
m.chai.expect(function() {
utils.percentageToFloat(-1);
}).to.throw('Invalid percentage: -1');
});
it('should throw an error if given a float percentage < 0', function() {
m.chai.expect(function() {
utils.percentageToFloat(-0.1);
}).to.throw('Invalid percentage: -0.1');
});
it('should covert a 0 percentage to 0', function() {
m.chai.expect(utils.percentageToFloat(0)).to.equal(0);
});
it('should covert an integer percentage to a float', function() {
m.chai.expect(utils.percentageToFloat(50)).to.equal(0.5);
});
it('should covert an float percentage to a float', function() {
m.chai.expect(utils.percentageToFloat(46.54)).to.equal(0.4654);
});
it('should covert a 100 percentage to 1', function() {
m.chai.expect(utils.percentageToFloat(100)).to.equal(1);
});
it('should throw an error if given an integer percentage > 100', function() {
m.chai.expect(function() {
utils.percentageToFloat(101);
}).to.throw('Invalid percentage: 101');
});
it('should throw an error if given a float percentage > 100', function() {
m.chai.expect(function() {
utils.percentageToFloat(100.01);
}).to.throw('Invalid percentage: 100.01');
});
});
});