Move burn state to ImageWriterService

Previously, the burn state lived in the controller, however if the user
moved to another page (the settings page for example) and then returned,
the progress state would be lost, leading to a broken progress bar.

Fixes: https://github.com/resin-io/etcher/issues/190
This commit is contained in:
Juan Cruz Viotti 2016-03-10 11:46:41 -04:00
parent 6367dd8a57
commit 793001e133
4 changed files with 81 additions and 26 deletions

View File

@ -35,6 +35,7 @@ require('./browser/modules/settings');
require('./browser/modules/drive-scanner');
require('./browser/modules/image-writer');
require('./browser/modules/path');
require('./browser/modules/notifier');
require('./browser/modules/analytics');
const app = angular.module('Etcher', [
@ -47,6 +48,7 @@ const app = angular.module('Etcher', [
'Etcher.settings',
'Etcher.drive-scanner',
'Etcher.image-writer',
'Etcher.notifier',
'Etcher.analytics'
]);
@ -74,6 +76,8 @@ app.config(function($stateProvider, $urlRouterProvider) {
app.controller('AppController', function(
$q,
$state,
$scope,
NotifierService,
DriveScannerService,
SelectionStateService,
ImageWriterService,
@ -87,12 +91,16 @@ app.controller('AppController', function(
AnalyticsService.logEvent('Restart');
if (!this.writer.isBurning()) {
this.state = {
progress: 0,
percentage: 0
};
this.writer.resetState();
}
NotifierService.subscribe($scope, 'image-writer:state', function(state) {
AnalyticsService.log(`Progress: ${state.progress}% at ${state.speed} MB/s`);
// Show progress inline in operating system task bar
currentWindow.setProgressBar(state.progress / 100);
});
this.scanner.start(2000).on('scan', function(drives) {
// Notice we only autoselect the drive if there is an image,
@ -183,14 +191,7 @@ app.controller('AppController', function(
device: drive.device
});
return self.writer.burn(image, drive, function(state) {
self.state = state;
AnalyticsService.log(`Progress: ${self.state.progress}% at ${self.state.speed} MB/s`);
// Show progress inline in operating system task bar
currentWindow.setProgressBar(self.state.progress / 100);
}).then(function() {
return self.writer.burn(image, drive).then(function() {
AnalyticsService.logEvent('Done');
$state.go('success');
}).catch(dialog.showError).finally(function() {

View File

@ -30,14 +30,39 @@ if (window.mocha) {
}
require('./settings');
require('./notifier');
const imageWriter = angular.module('Etcher.image-writer', [
'Etcher.settings'
'Etcher.settings',
'Etcher.notifier'
]);
imageWriter.service('ImageWriterService', function($q, $timeout, SettingsService) {
imageWriter.service('ImageWriterService', function($q, $timeout, SettingsService, NotifierService) {
let self = this;
let burning = false;
/**
* @summary Reset burn state
* @function
* @public
*
* @example
* ImageWriterService.resetState();
*/
this.resetState = function() {
self.state = {
progress: 0,
speed: 0
};
};
/**
* @summary Burn progress state
* @type Object
* @public
*/
this.state = {};
this.resetState();
/**
* @summary Check if currently burning
* @function
@ -102,11 +127,10 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsService
* @public
*
* @description
* This function will update `state.progress` with the current writing percentage.
* This function will update `ImageWriterService.state` with the current writing state.
*
* @param {String} image - image path
* @param {Object} drive - drive
* @param {Function} onProgress - in progress callback (state)
*
* @returns {Promise}
*
@ -117,7 +141,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsService
* console.log('Write completed!');
* });
*/
this.burn = function(image, drive, onProgress) {
this.burn = function(image, drive) {
if (self.isBurning()) {
return $q.reject(new Error('There is already a burn in progress'));
}
@ -129,13 +153,14 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsService
// Safely bring the state to the world of Angular
$timeout(function() {
return onProgress({
self.state = {
progress: Math.floor(state.percentage),
// Transform bytes to megabytes preserving only two decimal places
speed: Math.floor(state.speed / 1e+6 * 100) / 100 || 0
};
});
NotifierService.emit('image-writer:state', self.state);
});
}).finally(function() {

View File

@ -56,17 +56,17 @@
<hero-badge class="block space-vertical-medium" ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">3</hero-badge>
<div class="space-vertical-large">
<hero-progress-button percentage="{{ app.state.progress }}" ng-attr-active="{{ app.writer.isBurning() }}"
<hero-progress-button percentage="{{ app.writer.state.progress }}" ng-attr-active="{{ app.writer.isBurning() }}"
ng-click="app.burn(app.selection.getImage(), app.selection.getDrive())"
ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">
<span ng-show="app.state.progress == 100 && app.writer.isBurning()">Finishing...</span>
<span ng-show="app.state.progress == 0 && !app.writer.isBurning()">Burn!</span>
<span ng-show="app.state.progress == 0 && app.writer.isBurning() && !app.state.speed">Starting...</span>
<span ng-show="app.state.speed && app.state.progress != 100"
ng-bind="app.state.progress + '% '"></span>
<span ng-show="app.writer.state.progress == 100 && app.writer.isBurning()">Finishing...</span>
<span ng-show="app.writer.state.progress == 0 && !app.writer.isBurning()">Burn!</span>
<span ng-show="app.writer.state.progress == 0 && app.writer.isBurning() && !app.writer.state.speed">Starting...</span>
<span ng-show="app.writer.state.speed && app.writer.state.progress != 100"
ng-bind="app.writer.state.progress + '% '"></span>
</hero-progress-button>
<p class="step-footer" ng-bind="app.state.speed.toFixed(2) + ' MB/s'" ng-show="app.state.speed && app.state.progress != 100"></p>
<p class="step-footer" ng-bind="app.writer.state.speed.toFixed(2) + ' MB/s'" ng-show="app.writer.state.speed && app.writer.state.progress != 100"></p>
</div>
</div>
</div>

View File

@ -23,6 +23,35 @@ describe('Browser: ImageWriter', function() {
ImageWriterService = _ImageWriterService_;
}));
describe('.state', function() {
it('should be reset by default', function() {
m.chai.expect(ImageWriterService.state).to.deep.equal({
progress: 0,
speed: 0
});
});
});
describe('.resetState()', function() {
it('should be able to reset the state', function() {
ImageWriterService.state = {
progress: 50,
speed: 3
};
ImageWriterService.resetState();
m.chai.expect(ImageWriterService.state).to.deep.equal({
progress: 0,
speed: 0
});
});
});
describe('.isBurning()', function() {
it('should return false by default', function() {