Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1153)

Unified Diff: ui/file_manager/file_manager/foreground/js/import_controller.js

Issue 792233009: Reflect scanning status in command UI. Only allow import once scanning is complete. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix FM.jstests.cc && Finalize scan results in MediaImportHandlerTest...unbreaking the test. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/file_manager/file_manager/foreground/js/import_controller.js
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js
new file mode 100644
index 0000000000000000000000000000000000000000..6dfbfb8cbed5b21ee0376ef4a73fd8186feada35
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js
@@ -0,0 +1,250 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Namespace
+var importer = importer || {};
+
+/**
+ * @typedef {{
+ * label_id: string,
+ * visible: boolean,
+ * executable: boolean
+ * }}
+ */
+importer.UpdateResponse;
+
+/** @enum {importer.UpdateResponse} */
+importer.UpdateResponses = {
+ HIDDEN: {
+ label_id: 'CLOUD_IMPORT_BUTTON_LABEL',
+ visible: false,
+ executable: false
+ },
+ SCANNING: {
+ label_id: 'CLOUD_IMPORT_SCANNING_BUTTON_LABEL',
+ visible: true,
+ executable: false
+ },
+ EXECUTABLE: {
+ label_id: 'CLOUD_IMPORT_BUTTON_LABEL',
+ visible: true,
+ executable: true
+ }
+};
+
+/**
+ * Class that orchestrates background activity and UI changes on
+ * behalf of Cloud Import.
+ *
+ * @constructor
+ * @struct
+ *
+ * @param {!importer.ControllerEnvironment} environment The class providing
+ * access to runtime environmental information, like the current directory,
+ * volume lookup and so-on.
+ * @param {!importer.MediaScanner} scanner
+ * @param {!importer.ImportRunner} importRunner
+ * @param {function()} commandUpdateHandler
+ */
+importer.ImportController =
+ function(environment, scanner, importRunner, commandUpdateHandler) {
+
+ /** @private {!importer.ControllerEnvironment} */
+ this.environment_ = environment;
+
+ /** @private {!importer.ImportRunner} */
+ this.importRunner_ = importRunner;
+
+ /** @private {!importer.MediaScanner} */
+ this.scanner_ = scanner;
+
+ /** @private {function()} */
+ this.updateCommands_ = commandUpdateHandler;
+
+ /** @private {!importer.ScanObserver} */
+ this.scanObserverBound_ = this.onScanEvent_.bind(this);
+
+ this.scanner_.addObserver(this.scanObserverBound_);
+
+ /** @private {!Object.<string, !importer.ScanResult>} */
+ this.directoryScans_ = {};
+};
+
+/**
+ * @param {!importer.ScanEvent} event Command event.
+ * @param {importer.ScanResult} result
+ */
+importer.ImportController.prototype.onScanEvent_ = function(event, result) {
+ // TODO(smckay): only do this if this is a directory scan.
+ if (event === importer.ScanEvent.FINALIZED) {
+ this.updateCommands_();
+ }
+};
+
+/**
+ * Executes import against the current directory. Should only
+ * be called when the current directory has been validated
+ * by calling "update" on this class.
+ */
+importer.ImportController.prototype.execute = function() {
+ metrics.recordEnum('CloudImport.UserAction', 'IMPORT_INITIATED');
+ var result = this.getScanForImport_();
+ this.importRunner_.importFromScanResult(result);
+};
+
+/**
+ * @return {!importer.UpdateResponse} response
+ */
+importer.ImportController.prototype.update = function() {
+
+ // If there is no Google Drive mount, Drive may be disabled
+ // or the machine may be running in guest mode.
+ if (!this.environment_.isGoogleDriveMounted()) {
+ return importer.UpdateResponses.HIDDEN;
+ }
+
+ var entries = this.environment_.getSelection();
+
+ // Enabled if user has a selection and it consists entirely of files
+ // that:
+ // 1) are of a recognized media type
+ // 2) reside on a removable media device
+ // 3) in the DCIM dir
+ if (entries.length) {
+ if (entries.every(
+ importer.isEligibleEntry.bind(null, this.environment_))) {
+ // TODO(smckay): Include entry count in label.
+ return importer.UpdateResponses.EXECUTABLE;
+ }
+ } else if (this.isCurrentDirectoryScannable_()) {
+ var scan = this.getCurrentDirectoryScan_();
+ return scan.isFinal() ?
+ importer.UpdateResponses.EXECUTABLE :
+ importer.UpdateResponses.SCANNING;
+ }
+
+ return importer.UpdateResponses.HIDDEN;
+};
+
+/**
+ * @return {boolean} true if the current directory is scan eligible.
+ * @private
+ */
+importer.ImportController.prototype.isCurrentDirectoryScannable_ =
+ function() {
+ var directory = this.environment_.getCurrentDirectory();
+ return !!directory &&
+ importer.isMediaDirectory(directory, this.environment_);
+};
+
+/**
+ * Get or create scan for the current directory or file selection.
+ *
+ * @return {!importer.ScanResult} A scan result object that may be
+ * actively scanning.
+ * @private
+ */
+importer.ImportController.prototype.getScanForImport_ = function() {
+ var entries = this.environment_.getSelection();
+
+ if (entries.length) {
+ if (entries.every(
+ importer.isEligibleEntry.bind(null, this.environment_))) {
+ return this.scanner_.scan(entries);
+ }
+ } else {
+ return this.getCurrentDirectoryScan_();
+ }
+};
+
+/**
+ * Get or create scan for the current directory.
+ *
+ * @return {!importer.ScanResult} A scan result object that may be
+ * actively scanning.
+ * @private
+ */
+importer.ImportController.prototype.getCurrentDirectoryScan_ = function() {
+ console.assert(this.isCurrentDirectoryScannable_());
+ var directory = this.environment_.getCurrentDirectory();
+ var url = directory.toURL();
+ var scan = this.directoryScans_[url];
+ if (!scan) {
+ scan = this.scanner_.scan([directory]);
+ // TODO(smckay): evict scans when a device is unmounted or changed.
+ this.directoryScans_[url] = scan;
+ }
+ return scan;
+};
+
+/**
+ * Interface abstracting away the concrete file manager available
+ * to commands. By hiding file manager we make it easy to test
+ * ImportController.
+ *
+ * @interface
+ * @extends {VolumeManagerCommon.VolumeInfoProvider}
+ */
+importer.ControllerEnvironment = function() {};
+
+/**
+ * Returns the current file selection, if any. May be empty.
+ * @return {!Array.<!Entry>}
+ */
+importer.ControllerEnvironment.prototype.getSelection;
+
+/**
+ * Returns the directory entry for the current directory.
+ * @return {!DirectoryEntry}
+ */
+importer.ControllerEnvironment.prototype.getCurrentDirectory;
+
+/**
+ * Returns true if the Drive mount is present.
+ * @return {boolean}
+ */
+importer.ControllerEnvironment.prototype.isGoogleDriveMounted;
+
+
+/**
+ * Class providing access to various pieces of information in the
+ * FileManager environment, like the current directory, volumeinfo lookup
+ * By hiding file manager we make it easy to test importer.ImportController.
+ *
+ * @constructor
+ * @implements {importer.ControllerEnvironment}
+ *
+ * @param {!FileManager} fileManager
+ */
+importer.RuntimeControllerEnvironment = function(fileManager) {
+ /** @private {!FileManager} */
+ this.fileManager_ = fileManager;
+};
+
+/** @override */
+importer.RuntimeControllerEnvironment.prototype.getSelection =
+ function() {
+ return this.fileManager_.getSelection().entries;
+};
+
+/** @override */
+importer.RuntimeControllerEnvironment.prototype.getCurrentDirectory =
+ function() {
+ return /** @type {!DirectoryEntry} */ (
+ this.fileManager_.getCurrentDirectoryEntry());
+};
+
+/** @override */
+importer.RuntimeControllerEnvironment.prototype.getVolumeInfo =
+ function(entry) {
+ return this.fileManager_.volumeManager.getVolumeInfo(entry);
+};
+
+/** @override */
+importer.RuntimeControllerEnvironment.prototype.isGoogleDriveMounted =
+ function() {
+ var drive = this.fileManager_.volumeManager.getCurrentProfileVolumeInfo(
+ VolumeManagerCommon.VolumeType.DRIVE);
+ return !!drive;
+};

Powered by Google App Engine
This is Rietveld 408576698