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

Unified Diff: ui/file_manager/file_manager/background/js/media_import_handler.js

Issue 881463003: Files.app: Add a deduplication step to avoid importing duplicate media. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Sync to master; fix Banners test. Created 5 years, 11 months 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/background/js/media_import_handler.js
diff --git a/ui/file_manager/file_manager/background/js/media_import_handler.js b/ui/file_manager/file_manager/background/js/media_import_handler.js
index 2e8c0143b107fe5a25fb3b67b4985b407686cb6b..0135363a2493de1a1392f2277b1cf3c93141a121 100644
--- a/ui/file_manager/file_manager/background/js/media_import_handler.js
+++ b/ui/file_manager/file_manager/background/js/media_import_handler.js
@@ -13,12 +13,16 @@ var importer = importer || {};
importer.ImportRunner = function() {};
/**
+ * @typedef {function():(!Promise<!DirectoryEntry>)}
+ */
+importer.ImportRunner.DestinationFactory;
+
+/**
* Imports all media identified by scanResult.
*
* @param {!importer.ScanResult} scanResult
- * @param {!importer.MediaImportHandler.DestinationFactory=} opt_destination A
+ * @param {!importer.ImportRunner.DestinationFactory=} opt_destination A
* function that returns the directory into which media will be imported.
- * The function will be executed only when the import task actually runs.
*
* @return {!importer.MediaImportHandler.ImportTask} The resulting import task.
*/
@@ -33,8 +37,10 @@ importer.ImportRunner.prototype.importFromScanResult;
*
* @param {!ProgressCenter} progressCenter
* @param {!importer.HistoryLoader} historyLoader
+ * @param {!importer.DuplicateFinder} duplicateFinder
*/
-importer.MediaImportHandler = function(progressCenter, historyLoader) {
+importer.MediaImportHandler =
+ function(progressCenter, historyLoader, duplicateFinder) {
/** @private {!ProgressCenter} */
this.progressCenter_ = progressCenter;
@@ -44,19 +50,16 @@ importer.MediaImportHandler = function(progressCenter, historyLoader) {
/** @private {!importer.TaskQueue} */
this.queue_ = new importer.TaskQueue();
+ /** @private {!importer.DuplicateFinder} */
+ this.duplicateFinder_ = duplicateFinder;
+
/** @private {number} */
this.nextTaskId_ = 0;
};
-/**
- * @typedef {function():(!Promise<!DirectoryEntry>)}
- */
-importer.MediaImportHandler.DestinationFactory;
-
/** @override */
importer.MediaImportHandler.prototype.importFromScanResult =
function(scanResult, opt_destination) {
-
var destination = opt_destination ||
importer.MediaImportHandler.defaultDestination.getImportDestination;
@@ -64,9 +67,10 @@ importer.MediaImportHandler.prototype.importFromScanResult =
this.generateTaskId_(),
this.historyLoader_,
scanResult,
- destination);
+ destination,
+ this.duplicateFinder_);
- task.addObserver(this.onTaskProgress_.bind(this));
+ task.addObserver(this.onTaskProgress_.bind(this, task));
this.queue_.queueTask(task);
@@ -84,12 +88,12 @@ importer.MediaImportHandler.prototype.generateTaskId_ = function() {
/**
* Sends updates to the ProgressCenter when an import is happening.
*
- * @param {!importer.TaskQueue.UpdateType} updateType
* @param {!importer.TaskQueue.Task} task
+ * @param {string} updateType
* @private
*/
importer.MediaImportHandler.prototype.onTaskProgress_ =
- function(updateType, task) {
+ function(task, updateType) {
var UpdateType = importer.TaskQueue.UpdateType;
var item = this.progressCenter_.getItemById(task.taskId);
@@ -143,22 +147,28 @@ importer.MediaImportHandler.prototype.onTaskProgress_ =
* @param {string} taskId
* @param {!importer.HistoryLoader} historyLoader
* @param {!importer.ScanResult} scanResult
- * @param {!importer.MediaImportHandler.DestinationFactory} destinationFactory A
+ * @param {!importer.ImportRunner.DestinationFactory} destinationFactory A
* function that returns the directory into which media will be imported.
+ * @param {!importer.DuplicateFinder} duplicateFinder A duplicate-finder linked
+ * to the import destination, that will be used to deduplicate imports.
*/
importer.MediaImportHandler.ImportTask = function(
taskId,
historyLoader,
scanResult,
- destinationFactory) {
+ destinationFactory,
+ duplicateFinder) {
importer.TaskQueue.BaseTask.call(this, taskId);
/** @private {string} */
this.taskId_ = taskId;
- /** @private {!importer.MediaImportHandler.DestinationFactory} */
+ /** @private {!importer.ImportRunner.DestinationFactory} */
this.destinationFactory_ = destinationFactory;
+ /** @private {!importer.DuplicateFinder} */
+ this.deduplicator_ = duplicateFinder;
+
/** @private {!importer.ScanResult} */
this.scanResult_ = scanResult;
@@ -184,6 +194,24 @@ importer.MediaImportHandler.ImportTask = function(
this.canceled_ = false;
};
+/**
+ * Update types that are specific to ImportTask. Clients can add Observers to
+ * ImportTask to listen for these kinds of updates.
+ * @enum {string}
+ */
+importer.MediaImportHandler.ImportTask.UpdateType = {
+ ENTRY_CHANGED: 'ENTRY_CHANGED'
+};
+
+/**
+ * Auxilliary info for ENTRY_CHANGED notifications.
+ * @typedef {{
+ * sourceUrl: string,
+ * destination: !Entry
+ * }}
+ */
+importer.MediaImportHandler.ImportTask.EntryChangedInfo;
+
/** @struct */
importer.MediaImportHandler.ImportTask.prototype = {
/** @return {number} Number of imported bytes */
@@ -267,19 +295,47 @@ importer.MediaImportHandler.ImportTask.prototype.importTo_ =
* @param {function()} completionCallback Called after this operation is
* complete.
* @param {!FileEntry} entry The entry to import.
- * @param {number} index The entry's index in the scan results.
* @private
*/
importer.MediaImportHandler.ImportTask.prototype.importOne_ =
- function(destination, completionCallback, entry, index) {
+ function(destination, completionCallback, entry) {
if (this.canceled_) {
this.notify(importer.TaskQueue.UpdateType.CANCELED);
return;
}
+ this.deduplicator_.checkDuplicate(entry)
+ .then(
+ /** @param {boolean} isDuplicate */
+ function(isDuplicate) {
+ if (isDuplicate) {
+ // If the given file is a duplicate, don't import it again. Just
+ // update the progress indicator.
+ // TODO(kenobi): Update import history to mark the dupe as sync'd.
+ this.processedBytes_ += entry.size;
+ this.notify(importer.TaskQueue.UpdateType.PROGRESS);
+ return Promise.resolve();
+ } else {
+ return this.copy_(entry, destination);
+ }
+ }.bind(this))
+ .then(completionCallback);
+};
+
+/**
+ * @param {!FileEntry} entry The file to copy.
+ * @param {!DirectoryEntry} destination The destination directory.
+ * @return {!Promise<!FileEntry>} Resolves to the destination file when the copy
+ * is complete.
+ * @private
+ */
+importer.MediaImportHandler.ImportTask.prototype.copy_ =
+ function(entry, destination) {
// A count of the current number of processed bytes for this entry.
var currentBytes = 0;
+ var resolver = new importer.Resolver();
+
/**
* Updates the task when the copy code reports progress.
* @param {string} sourceUrl
@@ -297,28 +353,38 @@ importer.MediaImportHandler.ImportTask.prototype.importOne_ =
/**
* Updates the task when the new file has been created.
* @param {string} sourceUrl
- * @param {Entry} destEntry
+ * @param {Entry} destinationEntry
* @this {importer.MediaImportHandler.ImportTask}
*/
- var onEntryChanged = function(sourceUrl, destEntry) {
+ var onEntryChanged = function(sourceUrl, destinationEntry) {
this.processedBytes_ -= currentBytes;
this.processedBytes_ += entry.size;
- this.onEntryChanged_(sourceUrl, destEntry);
+ destinationEntry.size = entry.size;
+ this.notify(
+ importer.MediaImportHandler.ImportTask.UpdateType.ENTRY_CHANGED,
+ {
+ sourceUrl: sourceUrl,
+ destination: destinationEntry
+ });
this.notify(importer.TaskQueue.UpdateType.PROGRESS);
};
- /** @this {importer.MediaImportHandler.ImportTask} */
- var onComplete = function() {
+ /**
+ * @param {Entry} destinationEntry The new destination entry.
+ * @this {importer.MediaImportHandler.ImportTask}
+ */
+ var onComplete = function(destinationEntry) {
this.cancelCallback_ = null;
this.markAsCopied_(entry, destination);
this.notify(importer.TaskQueue.UpdateType.PROGRESS);
- completionCallback();
+ resolver.resolve(destinationEntry);
};
/** @this {importer.MediaImportHandler.ImportTask} */
var onError = function(error) {
this.cancelCallback_ = null;
this.onError_(error);
+ resolver.reject(error);
};
this.cancelCallback_ = fileOperationUtil.copyTo(
@@ -329,6 +395,8 @@ importer.MediaImportHandler.ImportTask.prototype.importOne_ =
onProgress.bind(this),
onComplete.bind(this),
onError.bind(this));
+
+ return resolver.promise;
};
/**
@@ -374,7 +442,7 @@ importer.MediaImportHandler.ImportTask.prototype.onError_ = function(error) {
/**
* Namespace for a default import destination factory. The
- * defaultDestionation.getImportDestination function creates and returns the
+ * defaultDestination.getImportDestination function creates and returns the
* directory /photos/YYYY-MM-DD in the user's Google Drive. YYYY-MM-DD is the
* current date.
*/

Powered by Google App Engine
This is Rietveld 408576698