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