Commit cf5fff0e authored by hirono's avatar hirono Committed by Commit bot

Add thumbnailMetadataItem to GalleryItem.

Previously the thumbnail metadata is obtained as a part of old metadata.  The CL
adds thumbnailMetadataItem to GalleryItem, and remove old metadata models from
Gallery.

BUG=410766
TEST=None

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

Cr-Commit-Position: refs/heads/master@{#319047}
parent e67565c3
......@@ -2,6 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Metadata containing thumbnail information.
* @typedef {Object}
*/
var ThumbnailMetadataItem;
/**
* @param {!MetadataModel} metadataModel
* @struct
......@@ -17,7 +23,8 @@ function ThumbnailModel(metadataModel) {
/**
* @param {!Array<!Entry>} entries
* @return {Promise} Promise fulfilled with old format metadata list.
* @return {Promise<ThumbnailMetadataItem>} Promise fulfilled with old format
* metadata list.
*/
ThumbnailModel.prototype.get = function(entries) {
var results = {};
......
......@@ -67,9 +67,7 @@ function Gallery(volumeManager) {
this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this);
this.initialized_ = false;
this.dataModel_ = new GalleryDataModel(
this.context_.metadataCache,
this.metadataModel_);
this.dataModel_ = new GalleryDataModel(this.metadataModel_);
var downloadVolumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo(
VolumeManagerCommon.VolumeType.DOWNLOADS);
downloadVolumeInfo.resolveDisplayRoot().then(function(entry) {
......@@ -260,7 +258,8 @@ Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|external';
* @const
* @type {!Array<string>}
*/
Gallery.PREFETCH_PROPERTY_NAMES = ['imageWidth', 'imageHeight', 'size'];
Gallery.PREFETCH_PROPERTY_NAMES =
['imageWidth', 'imageHeight', 'size', 'present'];
/**
* Closes gallery when a volume containing the selected item is unmounted.
......@@ -370,6 +369,7 @@ Gallery.prototype.loadInternal_ = function(entries, selectedEntries) {
// Load entries.
// Use the self variable capture-by-closure because it is faster than bind.
var self = this;
var thumbnailModel = new ThumbnailModel(this.metadataModel_);
var loadChunk = function(firstChunk) {
// Extract chunk.
var chunk = loadingList.splice(0, maxChunkSize);
......@@ -378,17 +378,10 @@ Gallery.prototype.loadInternal_ = function(entries, selectedEntries) {
var entries = chunk.map(function(chunkItem) {
return chunkItem.entry;
});
var oldMetadataPromise = new Promise(function(fulfill) {
// Obtains metadata for chunk.
self.metadataCache_.get(entries, Gallery.METADATA_TYPE, fulfill);
}).then(function(metadataList) {
if (chunk.length !== metadataList.length)
return Promise.reject('Failed to load metadata.');
return metadataList;
});
var metadataPromise = self.metadataModel_.get(
entries, Gallery.PREFETCH_PROPERTY_NAMES);
return Promise.all([oldMetadataPromise, metadataPromise]).then(
var thumbnailPromise = thumbnailModel.get(entries);
return Promise.all([metadataPromise, thumbnailPromise]).then(
function(metadataLists) {
// Remove all the previous items if it's the first chunk.
// Do it here because prevent a flicker between removing all the items
......@@ -404,15 +397,11 @@ Gallery.prototype.loadInternal_ = function(entries, selectedEntries) {
var locationInfo = self.volumeManager_.getLocationInfo(chunkItem.entry);
if (!locationInfo) // Skip the item, since gone.
return;
var clonedMetadata =
MetadataCache.cloneMetadata(metadataLists[0][index]);
items.push(new Gallery.Item(
chunkItem.entry,
locationInfo,
clonedMetadata,
metadataLists[0][index],
metadataLists[1][index],
self.metadataCache_,
self.metadataModel_,
/* original */ true));
});
self.dataModel_.push.apply(self.dataModel_, items);
......@@ -841,7 +830,7 @@ Gallery.prototype.onFilenameEditBlur_ = function(event) {
var event = new Event('content');
event.item = item;
event.oldEntry = oldEntry;
event.metadata = null; // Metadata unchanged.
event.thumbnailChanged = false;
this.dataModel_.dispatchEvent(event);
}.bind(this), function(error) {
if (error === 'NOT_CHANGED')
......
......@@ -5,22 +5,14 @@
/**
* Data model for gallery.
*
* @param {!MetadataCache} metadataCache Metadata cache.
* @param {!MetadataModel} metadataModel
* @param {!EntryListWatcher=} opt_watcher Entry list watcher.
* @constructor
* @extends {cr.ui.ArrayDataModel}
*/
function GalleryDataModel(metadataCache, metadataModel, opt_watcher) {
function GalleryDataModel(metadataModel, opt_watcher) {
cr.ui.ArrayDataModel.call(this, []);
/**
* Metadata cache.
* @private {!MetadataCache}
* @const
*/
this.metadataCache_ = metadataCache;
/**
* File system metadata.
* @private {!MetadataModel}
......@@ -72,12 +64,13 @@ GalleryDataModel.prototype = {
GalleryDataModel.prototype.saveItem = function(
volumeManager, item, canvas, overwrite) {
var oldEntry = item.getEntry();
var oldMetadata = item.getMetadata();
var oldMetadataItem = item.getMetadataItem();
var oldThumbnailMetadataItem = item.getThumbnailMetadataItem();
var oldLocationInfo = item.getLocationInfo();
return new Promise(function(fulfill, reject) {
item.saveToFile(
volumeManager,
this.metadataModel_,
this.fallbackSaveDirectory,
overwrite,
canvas,
......@@ -92,7 +85,7 @@ GalleryDataModel.prototype.saveItem = function(
var event = new Event('content');
event.item = item;
event.oldEntry = oldEntry;
event.metadata = item.getMetadata();
event.thumbnailChanged = true;
this.dispatchEvent(event);
if (!util.isSameEntry(oldEntry, item.getEntry())) {
......@@ -101,10 +94,8 @@ GalleryDataModel.prototype.saveItem = function(
var anotherItem = new Gallery.Item(
oldEntry,
oldLocationInfo,
oldMetadata,
oldMetadataItem,
this.metadataCache_,
this.metadataModel_,
oldThumbnailMetadataItem,
item.isOriginal());
// The item must be added behind the existing item so that it does
// not change the index of the existing item.
......
......@@ -8,17 +8,15 @@ var fileSystem;
var item;
function setUp() {
var metadataCache = new MockMetadataCache();
model = new GalleryDataModel(
metadataCache,
/* Mock MetadataModel */{},
/* Mock EntryListWatcher */{});
fileSystem = new MockFileSystem('volumeId');
item = new Gallery.Item(
new MockEntry(fileSystem, '/test.jpg'),
null,
{media: {mimeType: 'image/jpeg'}},
metadataCache,
/* metadataItem */ {},
/* thumbnailMetadataItem */ {},
/* original */ true);
}
......@@ -26,6 +24,7 @@ function testSaveItemOverwrite(callback) {
// Mocking the saveToFile method.
item.saveToFile = function(
volumeManager,
metadataModel,
fallbackDir,
overwrite,
canvas,
......@@ -44,6 +43,7 @@ function testSaveItemNewFile(callback) {
// Mocking the saveToFile method.
item.saveToFile = function(
volumeManager,
metadataModel,
fallbackDir,
overwrite,
canvas,
......
......@@ -7,53 +7,33 @@
*
* @param {!FileEntry} entry Image entry.
* @param {!EntryLocation} locationInfo Entry location information.
* @param {!Object} metadata Metadata for the entry.
* @param {!MetadataItem} metadataItem
* @param {!MetadataCache} metadataCache Metadata cache instance.
* @param {!MetadataModel} metadataModel File system metadata.
* @param {!ThumbnailMetadataItem} thumbnailMetadataItem
* @param {boolean} original Whether the entry is original or edited.
* @constructor
* @struct
*/
Gallery.Item = function(
entry, locationInfo, metadata, metadataItem, metadataCache,
metadataModel, original) {
entry, locationInfo, metadataItem, thumbnailMetadataItem, original) {
/**
* @type {!FileEntry}
* @private
* @private {!FileEntry}
*/
this.entry_ = entry;
/**
* @type {!EntryLocation}
* @private
* @private {!EntryLocation}
*/
this.locationInfo_ = locationInfo;
/**
* @type {!Object}
* @private
*/
this.metadata_ = Object.preventExtensions(metadata);
/**
* @type {!MetadataItem}
* @private {!MetadataItem}
*/
this.metadataItem_ = metadataItem;
/**
* @type {!MetadataCache}
* @private
* @const
*/
this.metadataCache_ = metadataCache;
/**
* @type {!MetadataModel}
* @private
* @const
* @private {!ThumbnailMetadataItem}
*/
this.metadataModel_ = metadataModel;
this.thumbnailMetadataItem_ = metadataItem;
// TODO(yawano): Change this.contentImage and this.screenImage to private
// fields and provide utility methods for them (e.g. revokeFullImageCache).
......@@ -101,9 +81,11 @@ Gallery.Item.prototype.getLocationInfo = function() {
};
/**
* @return {!Object} Metadata.
* @return {!MetadataItem} Metadata.
*/
Gallery.Item.prototype.getMetadata = function() { return this.metadata_; };
Gallery.Item.prototype.getMetadataItem = function() {
return this.metadataItem_;
};
/**
* @return {!MetadataItem} Metadata.
......@@ -112,6 +94,13 @@ Gallery.Item.prototype.getMetadataItem = function() {
return this.metadataItem_;
};
/**
* @return {!ThumbnailMetadataItem} Thumbnail metadata item.
*/
Gallery.Item.prototype.getThumbnailMetadataItem = function() {
return this.thumbnailMetadataItem_;
};
/**
* @return {string} File name.
*/
......@@ -224,6 +213,7 @@ Gallery.Item.prototype.createCopyName_ = function(dirEntry, callback) {
* Writes the new item content to either the existing or a new file.
*
* @param {!VolumeManager} volumeManager Volume manager instance.
* @param {!MetadataModel} metadataModel
* @param {DirectoryEntry} fallbackDir Fallback directory in case the current
* directory is read only.
* @param {boolean} overwrite Whether to overwrite the image to the item or not.
......@@ -231,7 +221,7 @@ Gallery.Item.prototype.createCopyName_ = function(dirEntry, callback) {
* @param {function(boolean)} callback Callback accepting true for success.
*/
Gallery.Item.prototype.saveToFile = function(
volumeManager, fallbackDir, overwrite, canvas, callback) {
volumeManager, metadataModel, fallbackDir, overwrite, canvas, callback) {
ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime'));
var name = this.getFileName();
......@@ -249,31 +239,17 @@ Gallery.Item.prototype.saveToFile = function(
this.locationInfo_ = locationInfo;
// Updates the metadata.
this.metadataCache_.clear([this.entry_], '*');
var oldMetadataPromise = new Promise(function(fulfill, reject) {
this.metadataCache_.getLatest(
[this.entry_],
Gallery.METADATA_TYPE,
function(metadataList) {
if (metadataList.length === 1) {
this.metadata_ = metadataList[0];
fulfill();
} else {
reject();
}
}.bind(this));
}.bind(this));
this.metadataModel_.notifyEntriesChanged([this.entry_]);
var newMetadataPromise = this.metadataModel_.get(
[entry], Gallery.PREFETCH_PROPERTY_NAMES).then(
function(metadataItems) {
this.metadataItem_ = metadataItems[0];
}.bind(this));
if (callback) {
Promise.all([oldMetadataPromise, newMetadataPromise]).then(
callback.bind(null, true),
callback.bind(null, false));
}
metadataModel.notifyEntriesChanged([this.entry_]);
Promise.all([
metadataModel.get([entry], Gallery.PREFETCH_PROPERTY_NAMES),
new ThumbnailModel(metadataModel).get([entry])
]).then(function(metadataLists) {
this.metadataItem_ = metadataLists[0][0];
this.thumbnailMetadataItem_ = metadataLists[1][0];
callback(true);
}.bind(this), function() {
callback(false);
});
}.bind(this);
var onError = function(error) {
......@@ -284,7 +260,7 @@ Gallery.Item.prototype.saveToFile = function(
};
var doSave = function(newFile, fileEntry) {
var metadataPromise = this.metadataModel_.get(
var metadataPromise = metadataModel.get(
[fileEntry],
['mediaMimeType', 'contentMimeType', 'ifd', 'exifLittleEndian']);
metadataPromise.then(function(metadataItems) {
......
......@@ -18,6 +18,7 @@ var Gallery = function() {};
<script src="../../file_manager/common/js/mock_entry.js"></script>
<script src="../../file_manager/common/js/unittest_util.js"></script>
<script src="../../file_manager/common/js/util.js"></script>
<script src="../../file_manager/foreground/js/metadata/thumbnail_model.js"></script>
<script src="gallery_item.js"></script>
<script src="gallery_item_unittest.js"></script>
......@@ -49,39 +49,34 @@ function testSaveToFile(callback) {
}
});
};
var fetchedMediaCleared = false;
var metadataCache = {
getLatest: function(entries, type, callback) {
callback([{name: 'newMetadata'}]);
var entryChanged = false;
var metadataModel = {
get: function(entries, names) {
return Promise.resolve([
{size: 200}
]);
},
clear: function(entries, type) {
fetchedMediaCleared = true;
notifyEntriesChanged: function() {
entryChanged = true;
}
};
var item = new Gallery.Item(
entry,
{isReadOnly: false},
{name: 'oldMetadata'},
{size: 100},
{},
metadataCache,
// Mock of MetadataModel.
{
get: function() {
return Promise.resolve([{}]);
},
notifyEntriesChanged: function() {}
},
/* original */ true);
assertEquals('oldMetadata', item.getMetadata().name);
assertFalse(fetchedMediaCleared);
assertEquals(100, item.getMetadataItem().size);
assertFalse(entryChanged);
reportPromise(
new Promise(item.saveToFile.bind(
item,
{getLocationInfo: function() { return {}; }},
null,
true,
metadataModel,
/* fallbackDir */ null,
/* overwrite */ true,
document.createElement('canvas'))).then(function() {
assertEquals('newMetadata', item.getMetadata().name);
assertTrue(fetchedMediaCleared);
assertEquals(200, item.getMetadataItem().size);
assertTrue(entryChanged);
}), callback);
}
......@@ -152,9 +152,10 @@ ImageView.getLoadTarget = function(item, effect) {
return ImageView.LoadTarget.CACHED_THUMBNAIL;
// Only show thumbnails if there is no effect or the effect is Slide.
var metadata = item.getMetadata();
var thumbnailLoader = new ThumbnailLoader(
item.getEntry(), ThumbnailLoader.LoaderType.CANVAS, item.getMetadata());
item.getEntry(),
ThumbnailLoader.LoaderType.CANVAS,
item.getThumbnailMetadataItem());
if ((effect instanceof ImageView.Effect.None ||
effect instanceof ImageView.Effect.Slide) &&
thumbnailLoader.getLoadTarget() !==
......@@ -350,7 +351,6 @@ ImageView.prototype.cancelLoad = function() {
ImageView.prototype.load =
function(item, effect, displayCallback, loadCallback) {
var entry = item.getEntry();
var metadata = item.getMetadata() || {};
if (!(effect instanceof ImageView.Effect.None)) {
// Skip effects when reloading repeatedly very quickly.
......@@ -389,7 +389,7 @@ ImageView.prototype.load =
var thumbnailLoader = new ThumbnailLoader(
entry,
ThumbnailLoader.LoaderType.CANVAS,
metadata);
item.getThumbnailMetadataItem());
thumbnailLoader.loadDetachedImage(function(success) {
displayThumbnail(
ImageView.LoadType.IMAGE_FILE,
......@@ -485,7 +485,7 @@ ImageView.prototype.load =
loadType, Object.keys(ImageView.LoadType).length);
if (loadType === ImageView.LoadType.ERROR &&
!navigator.onLine && !metadata.external.present) {
!navigator.onLine && !item.getMetadataItem().present) {
loadType = ImageView.LoadType.OFFLINE;
}
if (loadCallback) loadCallback(loadType, animationDuration, opt_error);
......
......@@ -547,7 +547,7 @@ Mosaic.prototype.onContentChange_ = function(event) {
if (!this.tiles_)
return;
if (!event.metadata)
if (!event.thumbnailChanged)
return; // Thumbnail unchanged, nothing to do.
var index = this.dataModel_.indexOf(event.item);
......@@ -2054,7 +2054,6 @@ Mosaic.Tile.prototype.markUnloaded = function() {
* target dimensions using metadata.
*/
Mosaic.Tile.prototype.init = function() {
var metadata = this.getItem().getMetadata();
this.markUnloaded();
this.left_ = null; // Mark as not laid out.
......@@ -2065,7 +2064,7 @@ Mosaic.Tile.prototype.init = function() {
this.thumbnailLoader_ = new ThumbnailLoader(
this.getItem().getEntry(),
ThumbnailLoader.LoaderType.CANVAS,
metadata,
this.getItem().getThumbnailMetadataItem(),
undefined, // Media type.
[
ThumbnailLoader.LoadTarget.EXTERNAL_METADATA,
......@@ -2079,7 +2078,7 @@ Mosaic.Tile.prototype.init = function() {
this.thumbnailPreloader_ = new ThumbnailLoader(
this.getItem().getEntry(),
ThumbnailLoader.LoaderType.CANVAS,
metadata,
this.getItem().getThumbnailMetadataItem(),
undefined, // Media type.
[
ThumbnailLoader.LoadTarget.CONTENT_METADATA
......
......@@ -98,13 +98,6 @@ function SlideMode(container, content, toolbar, prompt, errorBanner, dataModel,
*/
this.volumeManager_ = volumeManager;
/**
* @type {!MetadataCache}
* @private
* @const
*/
this.metadataCache_ = context.metadataCache;
/**
* @type {function(function())}
* @private
......
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