diff --git a/lib/browser/app.js b/lib/browser/app.js
index 6e9cef30..531331f2 100644
--- a/lib/browser/app.js
+++ b/lib/browser/app.js
@@ -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,
@@ -86,12 +90,12 @@ app.controller('AppController', function(
AnalyticsService.logEvent('Restart');
- if (!this.writer.isBurning()) {
- this.state = {
- progress: 0,
- percentage: 0
- };
- }
+ 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) {
@@ -183,14 +187,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() {
@@ -213,11 +210,12 @@ app.controller('NavigationController', function($state) {
this.open = shell.openExternal;
});
-app.controller('FinishController', function($state, SelectionStateService, SettingsService) {
+app.controller('FinishController', function($state, SelectionStateService, SettingsService, ImageWriterService) {
this.settings = SettingsService.data;
this.restart = function(options) {
SelectionStateService.clear(options);
+ ImageWriterService.resetState();
$state.go('main');
};
});
diff --git a/lib/browser/modules/image-writer.js b/lib/browser/modules/image-writer.js
index c87aaec9..84c64cbc 100644
--- a/lib/browser/modules/image-writer.js
+++ b/lib/browser/modules/image-writer.js
@@ -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() {
diff --git a/lib/browser/modules/notifier.js b/lib/browser/modules/notifier.js
new file mode 100644
index 00000000..7295a09f
--- /dev/null
+++ b/lib/browser/modules/notifier.js
@@ -0,0 +1,74 @@
+/*
+ * 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';
+
+/**
+ * @module Etcher.notifier
+ */
+
+const angular = require('angular');
+const notifier = angular.module('Etcher.notifier', []);
+
+/*
+ * Based on:
+ * http://www.codelord.net/2015/05/04/angularjs-notifying-about-changes-from-services-to-controllers/
+ */
+
+notifier.service('NotifierService', function($rootScope) {
+
+ /**
+ * @summary Safely subscribe to an event
+ * @function
+ * @public
+ *
+ * @description
+ * We say "safely" since this subscribe function will listen
+ * to the scope's `$destroy` event and unbind itself automatically.
+ *
+ * @param {Object} scope - angular scope
+ * @param {String} name - event name
+ * @param {Function} callback - callback
+ *
+ * @example
+ * NotifierService.subscribe($scope, 'my-event', function() {
+ * console.log('Event received!');
+ * });
+ */
+ this.subscribe = function(scope, name, callback) {
+ const handler = $rootScope.$on(name, function(event, data) {
+ return callback(data);
+ });
+
+ scope.$on('$destroy', handler);
+ };
+
+ /**
+ * @summary Emit an event
+ * @function
+ * @public
+ *
+ * @param {String} name - event name
+ * @param {*} data - event data
+ *
+ * @example
+ * NotifierService.emit('my-event', 'Foo');
+ */
+ this.emit = function(name, data) {
+ $rootScope.$emit(name, data);
+ };
+
+});
diff --git a/lib/partials/main.html b/lib/partials/main.html
index 820d07a6..716f0324 100644
--- a/lib/partials/main.html
+++ b/lib/partials/main.html
@@ -56,17 +56,17 @@