Commit d0bca741 authored by Luciano Pacheco's avatar Luciano Pacheco Committed by Commit Bot

Implement base interface and types for new navigation

Add interface FilesAppEntry which is the base interface that moving
forward the app UI will converge as base type that can be displayed on
different UI components such as: navigation tree, file list and
breadcrumbs, eventually superseding Entry type.

Add VolumeEntry which implements interface FilesAppEntry to represent a
Volume, this will allow to display Volumes on file list/Right Hand Side
(RHS).

Add EntryList which implements interface FilesAppEntry to represent a
list of entries.  This will be used to implement "My Files" which will
contain a list of VolumeEntry for the volumes: Downloads, Linux Files
(Crostini) and Play Files (ARC++).

Design doc: https://docs.google.com/document/d/1X5XSLKJd0yerL-qFhpb2z9ibUVb_W3gG_tfIV7T_Qt0

Bug: 846587, 835203
Test: Unit-test for the new types.
Cq-Include-Trybots: luci.chromium.try:closure_compilation
Change-Id: Ia2fce233338f8b8e0969b77daf4c77139852c441
Reviewed-on: https://chromium-review.googlesource.com/1086680
Commit-Queue: Luciano Pacheco <lucmult@chromium.org>
Reviewed-by: default avatarNoel Gordon <noel@chromium.org>
Reviewed-by: default avatarNaoki Fukino <fukino@chromium.org>
Reviewed-by: default avatarSasha Morrissey <sashab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572496}
parent d12baeba
......@@ -209,3 +209,8 @@ IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileListSelectionModelTest) {
RunTest(base::FilePath(FILE_PATH_LITERAL(
"foreground/js/ui/file_list_selection_model_unittest.html")));
}
IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FilesAppEntryTypes) {
RunTest(base::FilePath(
FILE_PATH_LITERAL("common/js/files_app_entry_types_unittest.html")));
}
......@@ -10,6 +10,7 @@ js_type_check("closure_compile") {
":closure_compile_externs",
":error_util",
":file_type",
":files_app_entry_types",
":importer_common",
":lru_cache",
":metrics",
......@@ -46,6 +47,9 @@ js_library("async_util") {
js_library("error_util") {
}
js_library("files_app_entry_types") {
}
js_library("file_type") {
}
......
<!DOCTYPE html>
<!-- Copyright 2018 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.
-->
<html>
<body>
<script src="../../common/js/unittest_util.js"></script>
<script src="files_app_entry_types.js"></script>
<script src="files_app_entry_types_unittest.js"></script>
</body>
</html>
// Copyright 2018 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.
'use strict';
/** Test constructor and default public attributes. */
function testEntryList(testReportCallback) {
const entryList = new EntryList('My Files', 'my_files');
assertEquals('My Files', entryList.label);
assertEquals('entry-list://my_files', entryList.toURL());
assertEquals('my_files', entryList.rootType);
assertFalse(entryList.isNativeType);
assertEquals(0, entryList.children.length);
assertTrue(entryList.isDirectory);
assertFalse(entryList.isFile);
entryList.addEntry(new EntryList('Child Entry', 'child_entry'));
assertEquals(1, entryList.children.length);
const reader = entryList.createReader();
// How many times the reader callback |accumulateResults| has been called?
let callCounter = 0;
// How many times it was called with results?
let resultCouter = 0;
const accumulateResults = (readerResult) => {
// It's called with readerResult==[] a last time to indicate no more files.
callCounter++;
if (readerResult.length > 0) {
resultCouter++;
reader.readEntries(accumulateResults);
}
};
reader.readEntries(accumulateResults);
// readEntries runs asynchronously, so let's wait it to be called.
reportPromise(
waitUntil(() => {
// accumulateResults should be called 2x in normal conditions;
return callCounter >= 2;
}).then(() => {
// Now we can check the final result.
assertEquals(2, callCounter);
assertEquals(1, resultCouter);
}),
testReportCallback);
}
/** Tests method EntryList.getParent. */
function testEntryListGetParent(testReportCallback) {
const entryList = new EntryList('My Files', 'my_files');
let callbackTriggered = false;
entryList.getParent(parentEntry => {
// EntryList should return itself since it's a root and that's what the web
// spec says.
callbackTriggered = true;
assertEquals(parentEntry, entryList);
});
reportPromise(waitUntil(() => callbackTriggered), testReportCallback);
}
/** Tests method EntryList.addEntry. */
function testEntryListAddEntry() {
const entryList = new EntryList('My Files');
assertEquals(0, entryList.children.length);
const fakeRootEntry = createFakeDisplayRoot();
const fakeVolumeInfo = {
displayRoot: fakeRootEntry,
label: 'Fake Filesystem',
};
const childEntry = new VolumeEntry(fakeVolumeInfo);
entryList.addEntry(childEntry);
assertEquals(1, entryList.children.length);
assertEquals(childEntry, entryList.children[0]);
}
/** Tests method EntryList.getMetadata. */
function testEntryListAddVolume(testReportCallback) {
const entryList = new EntryList('My Files');
let modificationTime = null;
entryList.getMetadata(metadata => {
modificationTime = metadata.modificationTime;
});
// getMetadata runs asynchronously, so let's wait it to be called.
reportPromise(
waitUntil(() => {
return modificationTime !== null;
}).then(() => {
// Now we can check the final result, it returns "now", so let's just
// check the type and 1 attribute here.
assertTrue(modificationTime instanceof Date);
assertTrue(!!modificationTime.getUTCFullYear());
}),
testReportCallback);
}
/** Tests StaticReader.readEntries. */
function testStaticReader(testReportCallback) {
const reader = new StaticReader(['file1', 'file2']);
const testResults = [];
// How many times the reader callback |accumulateResults| has been called?
let callCounter = 0;
const accumulateResults = (readerResult) => {
callCounter++;
// merge on testResults.
readerResult.map(f => testResults.push(f));
if (readerResult.length > 0)
reader.readEntries(accumulateResults);
};
reader.readEntries(accumulateResults);
// readEntries runs asynchronously, so let's wait it to be called.
reportPromise(
waitUntil(() => {
// accumulateResults should be called 2x in normal conditions;
return callCounter >= 2;
}).then(() => {
// Now we can check the final result.
assertEquals(2, callCounter);
assertEquals(2, testResults.length);
assertEquals('file1', testResults[0]);
assertEquals('file2', testResults[1]);
}),
testReportCallback);
}
/**
* Returns an object that can be used as displayRoot on a FakeVolumeInfo.
* VolumeEntry delegates many attributes and methods to displayRoot.
*/
function createFakeDisplayRoot() {
const fakeRootEntry = {
filesystem: 'fake-filesystem://',
fullPath: '/fake/full/path',
isDirectory: true,
isFile: false,
name: 'fs-name',
toURL: () => {
return 'fake-filesystem://fake/full/path';
},
createReader: () => {
return 'FAKE READER';
},
getMetadata: (success, error) => {
// Returns static date as modificationTime for testing.
setTimeout(
() => success({modificationTime: new Date(Date.UTC(2018, 6, 27))}));
},
};
return fakeRootEntry;
}
/**
* Tests VolumeEntry constructor and default public attributes/getter/methods.
*/
function testVolumeEntry() {
const fakeRootEntry = createFakeDisplayRoot();
const fakeVolumeInfo = {
displayRoot: fakeRootEntry,
label: 'Fake Filesystem',
};
const volumeEntry = new VolumeEntry(fakeVolumeInfo);
assertEquals(fakeRootEntry, volumeEntry.rootEntry);
assertEquals('fake-filesystem://', volumeEntry.filesystem);
assertEquals('/fake/full/path', volumeEntry.fullPath);
assertEquals('fake-filesystem://fake/full/path', volumeEntry.toURL());
assertEquals('Fake Filesystem', volumeEntry.name);
assertEquals('FAKE READER', volumeEntry.createReader());
assertTrue(volumeEntry.isNativeType);
assertTrue(volumeEntry.isDirectory);
assertFalse(volumeEntry.isFile);
}
/** Tests VolumeEntry.getParent */
function testVolumeEntryGetParent(testReportCallback) {
const fakeRootEntry = createFakeDisplayRoot();
const fakeVolumeInfo = {
displayRoot: fakeRootEntry,
label: 'Fake Filesystem',
};
const volumeEntry = new VolumeEntry(fakeVolumeInfo);
let callbackTriggered = false;
volumeEntry.getParent(parentEntry => {
callbackTriggered = true;
// VolumeEntry should return itself since it's a root and that's what the
// web spec says.
assertEquals(parentEntry, volumeEntry);
});
reportPromise(waitUntil(() => callbackTriggered), testReportCallback);
}
/** Tests VolumeEntry.getMetadata */
function testVolumeEntryGetMetadata(testReportCallback) {
const fakeRootEntry = createFakeDisplayRoot();
const fakeVolumeInfo = {
displayRoot: fakeRootEntry,
label: 'Fake Filesystem',
};
const volumeEntry = new VolumeEntry(fakeVolumeInfo);
let modificationTime = null;
volumeEntry.getMetadata(metadata => {
modificationTime = metadata.modificationTime;
});
// getMetadata runs asynchronously, so let's wait it to be called.
reportPromise(
waitUntil(() => {
return modificationTime !== null;
}).then(() => {
// Now we can check the final result.
assertEquals(2018, modificationTime.getUTCFullYear());
// Date() month is 0-based, so 6 == July. :-(
assertEquals(6, modificationTime.getUTCMonth());
assertEquals(27, modificationTime.getUTCDate());
}),
testReportCallback);
}
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