Commit d4f3217a authored by smckay's avatar smckay Committed by Commit bot

Eliminate last vestiges of the command system design.

Update ImportController to push all updates to a new 'CommandWidget' class. Add more test coverage.

BUG=420680
TEST=browser_test: FileManagerJsTest.*

Review URL: https://codereview.chromium.org/880303002

Cr-Commit-Position: refs/heads/master@{#313622}
parent 3244b994
...@@ -485,14 +485,13 @@ FileManager.prototype = /** @struct */ { ...@@ -485,14 +485,13 @@ FileManager.prototype = /** @struct */ {
importer.importEnabled().then( importer.importEnabled().then(
function(enabled) { function(enabled) {
if (enabled) { if (enabled) {
var commandAdapter = new importer.ButtonCommandAdapter(this);
this.importController_ = new importer.ImportController( this.importController_ = new importer.ImportController(
new importer.RuntimeControllerEnvironment(this), new importer.RuntimeControllerEnvironment(this),
/** @type {!importer.MediaScanner} */ ( /** @type {!importer.MediaScanner} */ (
this.mediaScanner_), this.mediaScanner_),
/** @type {!importer.ImportRunner} */ ( /** @type {!importer.ImportRunner} */ (
this.mediaImportHandler_), this.mediaImportHandler_),
commandAdapter.update.bind(commandAdapter)); new importer.RuntimeCommandWidget());
} }
}.bind(this)); }.bind(this));
......
...@@ -36,10 +36,10 @@ importer.CommandUpdate; ...@@ -36,10 +36,10 @@ importer.CommandUpdate;
* volume lookup and so-on. * volume lookup and so-on.
* @param {!importer.MediaScanner} scanner * @param {!importer.MediaScanner} scanner
* @param {!importer.ImportRunner} importRunner * @param {!importer.ImportRunner} importRunner
* @param {function()} commandUpdateHandler * @param {!importer.CommandWidget} commandWidget
*/ */
importer.ImportController = importer.ImportController =
function(environment, scanner, importRunner, commandUpdateHandler) { function(environment, scanner, importRunner, commandWidget) {
/** @private {!importer.ControllerEnvironment} */ /** @private {!importer.ControllerEnvironment} */
this.environment_ = environment; this.environment_ = environment;
...@@ -50,8 +50,8 @@ importer.ImportController = ...@@ -50,8 +50,8 @@ importer.ImportController =
/** @private {!importer.MediaScanner} */ /** @private {!importer.MediaScanner} */
this.scanner_ = scanner; this.scanner_ = scanner;
/** @private {function()} */ /** @private {!importer.CommandWidget} */
this.updateCommands_ = commandUpdateHandler; this.commandWidget_ = commandWidget;
/** /**
* A cache of scans by volumeId, directory URL. * A cache of scans by volumeId, directory URL.
...@@ -63,13 +63,20 @@ importer.ImportController = ...@@ -63,13 +63,20 @@ importer.ImportController =
var listener = this.onScanEvent_.bind(this); var listener = this.onScanEvent_.bind(this);
this.scanner_.addObserver(listener); this.scanner_.addObserver(listener);
// Remove the observer when the foreground window is closed. // Remove the observer when the foreground window is closed.
window.addEventListener('pagehide', function() { window.addEventListener(
this.scanner_.removeObserver(listener); 'pagehide',
}.bind(this)); function() {
this.scanner_.removeObserver(listener);
}.bind(this));
this.environment_.addVolumeUnmountListener( this.environment_.addVolumeUnmountListener(
this.onVolumeUnmounted_.bind(this)); this.onVolumeUnmounted_.bind(this));
this.environment_.addDirectoryChangedListener( this.environment_.addDirectoryChangedListener(
this.onDirectoryChanged_.bind(this)); this.onDirectoryChanged_.bind(this));
this.commandWidget_.addExecuteListener(
this.execute.bind(this));
}; };
/** /**
...@@ -90,7 +97,7 @@ importer.ImportController.prototype.onScanEvent_ = function(event, result) { ...@@ -90,7 +97,7 @@ importer.ImportController.prototype.onScanEvent_ = function(event, result) {
} }
if (event === importer.ScanEvent.FINALIZED || if (event === importer.ScanEvent.FINALIZED ||
event === importer.ScanEvent.INVALIDATED) { event === importer.ScanEvent.INVALIDATED) {
this.updateCommands_(); this.pushUpdate_();
} }
}; };
...@@ -106,8 +113,15 @@ importer.ImportController.prototype.execute = function() { ...@@ -106,8 +113,15 @@ importer.ImportController.prototype.execute = function() {
}; };
/** /**
* Called by the 'cloud-import' command when it wants an update * Push an update to the command widget.
* on the command state. * @private
*/
importer.ImportController.prototype.pushUpdate_ = function() {
this.commandWidget_.update(this.getCommandUpdate());
};
/**
* Returns an update describing the state of the CommandWidget.
* *
* @return {!importer.CommandUpdate} response * @return {!importer.CommandUpdate} response
*/ */
...@@ -264,14 +278,12 @@ importer.ImportController.prototype.onVolumeUnmounted_ = function(volumeId) { ...@@ -264,14 +278,12 @@ importer.ImportController.prototype.onVolumeUnmounted_ = function(volumeId) {
if (this.cachedScans_.hasOwnProperty(volumeId)) { if (this.cachedScans_.hasOwnProperty(volumeId)) {
delete this.cachedScans_[volumeId]; delete this.cachedScans_[volumeId];
} }
this.pushUpdate_();
}; };
/** /** @private */
* @param {string} volumeId
* @private
*/
importer.ImportController.prototype.onDirectoryChanged_ = function() { importer.ImportController.prototype.onDirectoryChanged_ = function() {
this.updateCommands_(); this.pushUpdate_();
}; };
/** /**
...@@ -398,49 +410,60 @@ importer.RuntimeControllerEnvironment.prototype.addDirectoryChangedListener = ...@@ -398,49 +410,60 @@ importer.RuntimeControllerEnvironment.prototype.addDirectoryChangedListener =
* Class that adapts from the new non-command button to the old * Class that adapts from the new non-command button to the old
* command style interface. * command style interface.
* *
* <p>NOTE: This adapter is a stop gap bridge between the old-style * @interface
* Command button and our new do-it-yourself toolbar button. We used */
* an adapter to minimize changes to RuntimeImportController while other importer.CommandWidget = function() {};
* people are working on that file. Once the dust settles we can make
* more transformative changes. /**
* * Install a listener that get's called when the user wants to initiate
* @constructor * import.
* @struct
* *
* @param {!FileManager} fileManager * @param {function()} listener
*/ */
importer.ButtonCommandAdapter = function(fileManager) { importer.CommandWidget.prototype.addExecuteListener;
/** @param {!FileManager} */ /**
this.fileManager_ = fileManager; * @param {!importer.CommandUpdate} update
*/
importer.CommandWidget.prototype.update;
/** @param {Element} */ /**
* Runtime implementation of CommandWidget.
*
* @constructor
* @implements {importer.CommandWidget}
* @struct
*/
importer.RuntimeCommandWidget = function() {
/** @private {Element} */
this.buttonElement_ = document.querySelector('#cloud-import-button'); this.buttonElement_ = document.querySelector('#cloud-import-button');
this.buttonElement_.onclick = this.execute_.bind(this); this.buttonElement_.onclick = this.notifyExecuteListener_.bind(this);
/** @param {Element} */ /** @private {Element} */
this.iconElement_ = document.querySelector('#cloud-import-button core-icon'); this.iconElement_ = document.querySelector('#cloud-import-button core-icon');
/** @private {function()} */
this.listener_;
};
/** @override */
importer.RuntimeCommandWidget.prototype.addExecuteListener =
function(listener) {
console.assert(!this.listener_);
this.listener_ = listener;
}; };
/** @private */ /** @private */
importer.ButtonCommandAdapter.prototype.execute_ = function() { importer.RuntimeCommandWidget.prototype.notifyExecuteListener_ = function() {
this.fileManager_.importController.execute(); console.assert(!!this.listener_);
this.listener_();
}; };
/** /** @override */
* @param {!Event} event Command event. importer.RuntimeCommandWidget.prototype.update = function(update) {
* @param {!FileManager} fileManager
*/
importer.ButtonCommandAdapter.prototype.update = function() {
if (this.fileManager_.importController) {
var update = fileManager.importController.getCommandUpdate();
this.buttonElement_.setAttribute('title', update.label); this.buttonElement_.setAttribute('title', update.label);
this.buttonElement_.disabled = !update.executable; this.buttonElement_.disabled = !update.executable;
this.buttonElement_.style.display = update.visible ? 'block' : 'none'; this.buttonElement_.style.display = update.visible ? 'block' : 'none';
this.iconElement_.setAttribute('icon', update.coreIcon); this.iconElement_.setAttribute('icon', update.coreIcon);
} else {
this.buttonElement_.setAttribute('display', 'none');
this.iconElement_.setAttribute('icon', 'cloud-off');
}
}; };
...@@ -20,8 +20,8 @@ var sourceVolume; ...@@ -20,8 +20,8 @@ var sourceVolume;
/** @type {!VolumeInfo} */ /** @type {!VolumeInfo} */
var destinationVolume; var destinationVolume;
/** @type {!TestCallRecorder} */ /** @type {!importer.TestCommandWidget} */
var commandUpdateRecorder; var widget;
// Set up string assets. // Set up string assets.
loadTimeData.data = { loadTimeData.data = {
...@@ -39,7 +39,7 @@ function setUp() { ...@@ -39,7 +39,7 @@ function setUp() {
recordEnum: function() {} recordEnum: function() {}
}; };
commandUpdateRecorder = new TestCallRecorder(); widget = new importer.TestCommandWidget();
volumeManager = new MockVolumeManager(); volumeManager = new MockVolumeManager();
MockVolumeManager.installMockSingleton(volumeManager); MockVolumeManager.installMockSingleton(volumeManager);
...@@ -113,7 +113,7 @@ function testGetCommandUpdate_InitiatesScan() { ...@@ -113,7 +113,7 @@ function testGetCommandUpdate_InitiatesScan() {
mediaScanner.assertScanCount(1); mediaScanner.assertScanCount(1);
} }
function testDirectoryChange_InitiatesUpdate() { function testDirectoryChange_PushesUpdate() {
var controller = createController( var controller = createController(
VolumeManagerCommon.VolumeType.MTP, VolumeManagerCommon.VolumeType.MTP,
'mtp-volume', 'mtp-volume',
...@@ -121,15 +121,11 @@ function testDirectoryChange_InitiatesUpdate() { ...@@ -121,15 +121,11 @@ function testDirectoryChange_InitiatesUpdate() {
'/DCIM/', '/DCIM/',
'/DCIM/photos0/', '/DCIM/photos0/',
'/DCIM/photos0/IMG00001.jpg', '/DCIM/photos0/IMG00001.jpg',
'/DCIM/photos0/IMG00002.jpg',
'/DCIM/photos1/',
'/DCIM/photos1/IMG00001.jpg',
'/DCIM/photos1/IMG00003.jpg'
], ],
'/DCIM'); '/DCIM');
environment.directoryChangedListener_(); environment.directoryChangedListener_();
commandUpdateRecorder.assertCallCount(1); widget.updates.assertCallCount(1);
} }
function testUnmountInvalidatesScans() { function testUnmountInvalidatesScans() {
...@@ -157,6 +153,23 @@ function testUnmountInvalidatesScans() { ...@@ -157,6 +153,23 @@ function testUnmountInvalidatesScans() {
mediaScanner.assertScanCount(2); mediaScanner.assertScanCount(2);
} }
function testVolumeUnmount_PushesUpdate() {
var controller = createController(
VolumeManagerCommon.VolumeType.MTP,
'mtp-volume',
[
'/DCIM/',
'/DCIM/photos0/',
'/DCIM/photos0/IMG00001.jpg',
],
'/DCIM');
// Faux unmount the volume, then request an update again.
// A fresh new scan should be started.
environment.simulateUnmount();
widget.updates.assertCallCount(1);
}
function testGetCommandUpdate_CanExecuteAfterScanIsFinalized() { function testGetCommandUpdate_CanExecuteAfterScanIsFinalized() {
var controller = createController( var controller = createController(
VolumeManagerCommon.VolumeType.MTP, VolumeManagerCommon.VolumeType.MTP,
...@@ -183,6 +196,26 @@ function testGetCommandUpdate_CanExecuteAfterScanIsFinalized() { ...@@ -183,6 +196,26 @@ function testGetCommandUpdate_CanExecuteAfterScanIsFinalized() {
assertTrue(response.executable); assertTrue(response.executable);
} }
function testFinalizeScans_PushesUpdate() {
var controller = createController(
VolumeManagerCommon.VolumeType.MTP,
'mtp-volume',
[
'/DCIM/',
'/DCIM/photos0/',
'/DCIM/photos0/IMG00001.jpg',
],
'/DCIM');
var fileSystem = new MockFileSystem('testFs');
mediaScanner.fileEntries.push(
new MockFileEntry(fileSystem, '/DCIM/photos0/IMG00001.jpg', {size: 0}));
controller.getCommandUpdate();
mediaScanner.finalizeScans();
widget.updates.assertCallCount(1);
}
function testGetCommandUpdate_CannotExecuteEmptyScanResult() { function testGetCommandUpdate_CannotExecuteEmptyScanResult() {
var controller = createController( var controller = createController(
VolumeManagerCommon.VolumeType.MTP, VolumeManagerCommon.VolumeType.MTP,
...@@ -206,7 +239,7 @@ function testGetCommandUpdate_CannotExecuteEmptyScanResult() { ...@@ -206,7 +239,7 @@ function testGetCommandUpdate_CannotExecuteEmptyScanResult() {
assertFalse(response.executable); assertFalse(response.executable);
} }
function testExecute_StartsImport() { function testClick_StartsImport() {
var controller = createController( var controller = createController(
VolumeManagerCommon.VolumeType.MTP, VolumeManagerCommon.VolumeType.MTP,
'mtp-volume', 'mtp-volume',
...@@ -215,16 +248,12 @@ function testExecute_StartsImport() { ...@@ -215,16 +248,12 @@ function testExecute_StartsImport() {
'/DCIM/photos0/', '/DCIM/photos0/',
'/DCIM/photos0/IMG00001.jpg', '/DCIM/photos0/IMG00001.jpg',
'/DCIM/photos0/IMG00002.jpg', '/DCIM/photos0/IMG00002.jpg',
'/DCIM/photos1/',
'/DCIM/photos1/IMG00001.jpg',
'/DCIM/photos1/IMG00003.jpg'
], ],
'/DCIM'); '/DCIM');
controller.getCommandUpdate(); // First we need to force the controller into a scanning state.
mediaScanner.finalizeScans(); environment.directoryChangedListener_();
controller.getCommandUpdate(); widget.executeListener();
controller.execute();
mediaImporter.assertImportsStarted(1); mediaImporter.assertImportsStarted(1);
} }
...@@ -372,6 +401,32 @@ TestControllerEnvironment.prototype.whenCurrentDirectoryIsSet = function() { ...@@ -372,6 +401,32 @@ TestControllerEnvironment.prototype.whenCurrentDirectoryIsSet = function() {
return this.directoryWasSetPromise_; return this.directoryWasSetPromise_;
}; };
/**
* Test implementation of importer.CommandWidget.
*
* @constructor
* @implements {importer.CommandWidget}
* @struct
*/
importer.TestCommandWidget = function() {
/** @public {function()} */
this.executeListener;
/** @public {!TestCallRecorder} */
this.updates = new TestCallRecorder();
};
/** @override */
importer.TestCommandWidget.prototype.addExecuteListener = function(listener) {
this.executeListener = listener;
};
/** @override */
importer.TestCommandWidget.prototype.update = function(update) {
this.updates.callback(update);
};
/** /**
* @param {!VolumeManagerCommon.VolumeType} volumeType * @param {!VolumeManagerCommon.VolumeType} volumeType
* @param {string} volumeId * @param {string} volumeId
...@@ -393,7 +448,7 @@ function createController(volumeType, volumeId, fileNames, currentDirectory) { ...@@ -393,7 +448,7 @@ function createController(volumeType, volumeId, fileNames, currentDirectory) {
environment, environment,
mediaScanner, mediaScanner,
mediaImporter, mediaImporter,
commandUpdateRecorder.callback); widget);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment