Skip to content

Commit

Permalink
Files app: Add share options menu on toolbar.
Browse files Browse the repository at this point in the history
This CL to divide tasks to open tasks and other tasks.
  open tasks: Files app internal tasks and file_hander tasks with OPEN_WITH verb.
  other tasks: all other tasks.

The OPEN combubutton should have only open tasks, and the new option menu should
have the other tasks. The new option menu has share icon as most of tasks should
be SHARE_WITH tasks, but other kind of tasks (e.g. PACK_WITH) can also be
included.

Existing share{_white}.png was renamed as person_add{_white}.png and the new
icon for share button was named as share{_white}.png, to be consistent with
the naming in go/icons.

Bug: 740819
Change-Id: Ic5e82aed490af9372e300c5153b5a384b6656464
Reviewed-on: https://chromium-review.googlesource.com/567917
Reviewed-by: Tatsuhisa Yamaguchi <yamaguchi@chromium.org>
Commit-Queue: Naoki Fukino <fukino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#486316}
  • Loading branch information
Naoki Fukino authored and Commit Bot committed Jul 13, 2017
1 parent 8b46473 commit ef2e848
Show file tree
Hide file tree
Showing 16 changed files with 184 additions and 78 deletions.
3 changes: 3 additions & 0 deletions chrome/app/chromeos_strings.grdp
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,9 @@ Press any key to continue exploring.
<message name="IDS_FILE_BROWSER_THUMBNAIL_VIEW_TOOLTIP" desc="Tooltip for the Thumbnail View button.">
Thumbnail view
</message>
<message name="IDS_FILE_BROWSER_SHARE_BUTTON_TOOLTIP" desc="Tooltip for the button which provides share options in the Files app.">
Share options
</message>
<message name="IDS_FILE_BROWSER_SORT_BUTTON_TOOLTIP" desc="Tooltip for the button which provides sort options in the Files app.">
Sort options
</message>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ ExtensionFunction::ResponseAction FileManagerPrivateGetStringsFunction::Run() {
SET_STRING("FORMATTING_WARNING", IDS_FILE_BROWSER_FORMATTING_WARNING);
SET_STRING("FORMAT_DEVICE_BUTTON_LABEL",
IDS_FILE_BROWSER_FORMAT_DEVICE_BUTTON_LABEL);
SET_STRING("SHARE_BUTTON_TOOLTIP", IDS_FILE_BROWSER_SHARE_BUTTON_TOOLTIP);
SET_STRING("SORT_BUTTON_TOOLTIP", IDS_FILE_BROWSER_SORT_BUTTON_TOOLTIP);
SET_STRING("GEAR_BUTTON_TOOLTIP", IDS_FILE_BROWSER_GEAR_BUTTON_TOOLTIP);
SET_STRING("GET_INFO_BUTTON_LABEL", IDS_FILE_BROWSER_GET_INFO_BUTTON_LABEL);
Expand Down
18 changes: 16 additions & 2 deletions ui/file_manager/file_manager/foreground/css/file_manager.css
Original file line number Diff line number Diff line change
Expand Up @@ -351,18 +351,30 @@ body.check-select #search-button > .icon {
url(../images/files/ui/2x/search.png) 2x);
}

#share-button > .icon {
#share-menu-button > .icon {
background-image: -webkit-image-set(
url(../images/files/ui/share_white.png) 1x,
url(../images/files/ui/2x/share_white.png) 2x);
}

body.check-select #share-button > .icon {
body.check-select #share-menu-button > .icon {
background-image: -webkit-image-set(
url(../images/files/ui/share.png) 1x,
url(../images/files/ui/2x/share.png) 2x);
}

#share-button > .icon {
background-image: -webkit-image-set(
url(../images/files/ui/person_add_white.png) 1x,
url(../images/files/ui/2x/person_add_white.png) 2x);
}

body.check-select #share-button > .icon {
background-image: -webkit-image-set(
url(../images/files/ui/person_add.png) 1x,
url(../images/files/ui/2x/person_add.png) 2x);
}

#delete-button > .icon {
background-image: -webkit-image-set(
url(../images/files/ui/delete_white.png) 1x,
Expand Down Expand Up @@ -1627,6 +1639,7 @@ body.check-select #list-container list li[selected] .detail-thumbnail
opacity: 0;
}

#share-menu cr-menu-item,
#tasks-menu cr-menu-item:not(.change-default) {
background-position: left 10px center;
padding-left: 32px;
Expand Down Expand Up @@ -1915,6 +1928,7 @@ list.autocomplete-suggestions > [lead] {
}

#gear-menu,
#share-menu,
#sort-menu,
#tasks-menu {
margin-top: 2px;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified ui/file_manager/file_manager/foreground/images/files/ui/share.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
102 changes: 79 additions & 23 deletions ui/file_manager/file_manager/foreground/js/file_tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,19 @@ FileTasks.isInternalTask_ = function(taskId) {
actionId === 'mount-archive');
};

/**
* Returns true if the given task is categorized as an OPEN task.
*
* @param {!Object} task
* @return {boolean} True if the given task is an OPEN task.
*/
FileTasks.isOpenTask = function(task) {
// We consider following types of tasks as OPEN tasks.
// - Files app's internal tasks
// - file_handler tasks with OPEN_WITH verb
return !task.verb || task.verb == chrome.fileManagerPrivate.Verb.OPEN_WITH;
};

/**
* Annotates tasks returned from the API.
*
Expand Down Expand Up @@ -658,25 +671,43 @@ FileTasks.prototype.mountArchivesInternal_ = function() {
};

/**
* Displays the list of tasks in a task picker combobutton.
* Displays the list of tasks in a open task picker combobutton and a share
* options menu.
*
* @param {cr.ui.ComboButton} combobutton The task picker element.
* @param {!cr.ui.ComboButton} openCombobutton The open task picker combobutton.
* @param {!cr.ui.MenuButton} shareMenuButton The menu button for share options.
* @public
*/
FileTasks.prototype.display = function(combobutton) {
// If there does not exist available task, hide combobutton.
if (this.tasks_.length === 0) {
combobutton.hidden = true;
return;
FileTasks.prototype.display = function(openCombobutton, shareMenuButton) {
var openTasks = [];
var otherTasks = [];
for (var i = 0; i < this.tasks_.length; i++) {
var task = this.tasks_[i];
if (FileTasks.isOpenTask(task))
openTasks.push(task);
else
otherTasks.push(task);
}
this.updateOpenComboButton_(openCombobutton, openTasks);
this.updateShareMenuButton_(shareMenuButton, otherTasks);
};

/**
* Setup a task picker combobutton based on the given tasks.
* @param {!cr.ui.ComboButton} combobutton
* @param {!Array<!Object>} tasks
*/
FileTasks.prototype.updateOpenComboButton_ = function(combobutton, tasks) {
combobutton.hidden = tasks.length == 0;
if (tasks.length == 0)
return;

combobutton.clear();
combobutton.hidden = false;

// If there exist defaultTask show it on the combobutton.
if (this.defaultTask_) {
combobutton.defaultItem = this.createCombobuttonItem_(this.defaultTask_,
str('TASK_OPEN'));
combobutton.defaultItem =
this.createCombobuttonItem_(this.defaultTask_, str('TASK_OPEN'));
} else {
combobutton.defaultItem = {
type: FileTasks.TaskMenuButtonItemType.ShowMenu,
Expand All @@ -687,7 +718,7 @@ FileTasks.prototype.display = function(combobutton) {
// If there exist 2 or more available tasks, show them in context menu
// (including defaultTask). If only one generic task is available, we
// also show it in the context menu.
var items = this.createItems_();
var items = this.createItems_(tasks);
if (items.length > 1 || (items.length === 1 && this.defaultTask_ === null)) {
for (var j = 0; j < items.length; j++) {
combobutton.addDropDownItem(items[j]);
Expand All @@ -706,19 +737,43 @@ FileTasks.prototype.display = function(combobutton) {
}
};

/**
* Setup a menu button for sharing options based on the given tasks.
* @param {!cr.ui.MenuButton} shareMenuButton
* @param {!Array<!Object>} tasks
*/
FileTasks.prototype.updateShareMenuButton_ = function(shareMenuButton, tasks) {
shareMenuButton.hidden = tasks.length == 0;
if (tasks.length == 0)
return;

shareMenuButton.menu.clear();
var items = this.createItems_(tasks);
for (var i = 0; i < items.length; i++) {
var menuitem = shareMenuButton.menu.addMenuItem(items[i]);
cr.ui.decorate(menuitem, cr.ui.FilesMenuItem);
menuitem.data = items[i];
if (items[i].iconType) {
menuitem.style.backgroundImage = '';
menuitem.setAttribute('file-type-icon', items[i].iconType);
}
}
};

/**
* Creates sorted array of available task descriptions such as title and icon.
*
* @param {!Array<!Object>} tasks Tasks to create items.
* @return {!Array<!Object>} Created array can be used to feed combobox, menus
* and so on.
* @private
*/
FileTasks.prototype.createItems_ = function() {
FileTasks.prototype.createItems_ = function(tasks) {
var items = [];

// Create items.
for (var index = 0; index < this.tasks_.length; index++) {
var task = this.tasks_[index];
for (var index = 0; index < tasks.length; index++) {
var task = tasks[index];
if (task === this.defaultTask_) {
var title = task.title + ' ' +
loadTimeData.getString('DEFAULT_TASK_LABEL');
Expand Down Expand Up @@ -781,16 +836,17 @@ FileTasks.prototype.createCombobuttonItem_ = function(task, opt_title,
* @param {string} title Title to use.
* @param {string} message Message to use.
* @param {function(Object)} onSuccess Callback to pass selected task.
* @param {boolean=} opt_hideGenericFileHandler Whether to hide generic file
* handler or not.
* @param {boolean=} opt_forChangeDefault Whether to return items which are for
* change-default dialog.
*/
FileTasks.prototype.showTaskPicker = function(taskDialog, title, message,
onSuccess,
opt_hideGenericFileHandler) {
var items = !opt_hideGenericFileHandler ? this.createItems_() :
this.createItems_().filter(function(item) {
return !item.isGenericFileHandler;
});
FileTasks.prototype.showTaskPicker = function(
taskDialog, title, message, onSuccess, opt_forChangeDefault) {
var items = !opt_forChangeDefault ?
this.createItems_(this.tasks_) :
this.createItems_(this.tasks_.filter(FileTasks.isOpenTask))
.filter(function(item) {
return !item.isGenericFileHandler;
});

var defaultIdx = 0;
for (var j = 0; j < items.length; j++) {
Expand Down
94 changes: 50 additions & 44 deletions ui/file_manager/file_manager/foreground/js/task_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ function TaskController(

ui.taskMenuButton.addEventListener(
'select', this.onTaskItemClicked_.bind(this));
ui.shareMenuButton.menu.addEventListener(
'activate', this.onTaskItemClicked_.bind(this));
this.selectionHandler_.addEventListener(
FileSelectionHandler.EventType.CHANGE,
this.onSelectionChanged_.bind(this));
Expand Down Expand Up @@ -146,51 +148,54 @@ TaskController.createTemporaryDisabledTaskItem_ = function() {
* @private
*/
TaskController.prototype.onTaskItemClicked_ = function(event) {
// 'select' event from ComboButton has the item as event.item.
// 'activate' event from cr.ui.MenuButton has the item as event.target.data.
var item = event.item || event.target.data;
this.getFileTasks()
.then(function(tasks) {
switch (event.item.type) {
case FileTasks.TaskMenuButtonItemType.ShowMenu:
this.ui_.taskMenuButton.showMenu(false);
break;
case FileTasks.TaskMenuButtonItemType.RunTask:
tasks.execute(event.item.task.taskId);
break;
case FileTasks.TaskMenuButtonItemType.ChangeDefaultTask:
var selection = this.selectionHandler_.selection;
var extensions = [];

for (var i = 0; i < selection.entries.length; i++) {
var match = /\.(\w+)$/g.exec(selection.entries[i].toURL());
if (match) {
var ext = match[1].toUpperCase();
if (extensions.indexOf(ext) == -1) {
extensions.push(ext);
.then(function(tasks) {
switch (item.type) {
case FileTasks.TaskMenuButtonItemType.ShowMenu:
this.ui_.taskMenuButton.showMenu(false);
break;
case FileTasks.TaskMenuButtonItemType.RunTask:
tasks.execute(item.task.taskId);
break;
case FileTasks.TaskMenuButtonItemType.ChangeDefaultTask:
var selection = this.selectionHandler_.selection;
var extensions = [];

for (var i = 0; i < selection.entries.length; i++) {
var match = /\.(\w+)$/g.exec(selection.entries[i].toURL());
if (match) {
var ext = match[1].toUpperCase();
if (extensions.indexOf(ext) == -1) {
extensions.push(ext);
}
}
}
}

var format = '';

if (extensions.length == 1) {
format = extensions[0];
}

// Change default was clicked. We should open "change default" dialog.
tasks.showTaskPicker(
this.ui_.defaultTaskPicker,
loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM'),
strf('CHANGE_DEFAULT_CAPTION', format),
this.changeDefaultTask_.bind(this, selection),
true);
break;
default:
assertNotReached('Unknown task.');
}
}.bind(this))
.catch(function(error) {
if (error)
console.error(error.stack || error);
});

var format = '';

if (extensions.length == 1) {
format = extensions[0];
}

// Change default was clicked. We should open "change default"
// dialog.
tasks.showTaskPicker(
this.ui_.defaultTaskPicker,
loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM'),
strf('CHANGE_DEFAULT_CAPTION', format),
this.changeDefaultTask_.bind(this, selection), true);
break;
default:
assertNotReached('Unknown task.');
}
}.bind(this))
.catch(function(error) {
if (error)
console.error(error.stack || error);
});
};

/**
Expand Down Expand Up @@ -218,7 +223,7 @@ TaskController.prototype.changeDefaultTask_ = function(selection, task) {
this.tasks_ = null;
this.getFileTasks()
.then(function(tasks) {
tasks.display(this.ui_.taskMenuButton);
tasks.display(this.ui_.taskMenuButton, this.ui_.shareMenuButton);
}.bind(this))
.catch(function(error) {
if (error)
Expand Down Expand Up @@ -303,7 +308,7 @@ TaskController.prototype.updateTasks_ = function() {
(selection.directoryCount > 0 || selection.fileCount > 0)) {
this.getFileTasks()
.then(function(tasks) {
tasks.display(this.ui_.taskMenuButton);
tasks.display(this.ui_.taskMenuButton, this.ui_.shareMenuButton);
this.updateContextMenuTaskItems_(tasks.getTaskItems());
}.bind(this))
.catch(function(error) {
Expand All @@ -312,6 +317,7 @@ TaskController.prototype.updateTasks_ = function() {
});
} else {
this.ui_.taskMenuButton.hidden = true;
this.ui_.shareMenuButton.hidden = true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ function testExecuteEntryTask(callback) {
fileSystem.entries['/test.png'] =
new MockFileEntry(fileSystem, '/test.png', {});
var controller = new TaskController(
DialogType.FULL_PAGE,
{
DialogType.FULL_PAGE, {
getDriveConnectionState: function() {
return VolumeManagerCommon.DriveConnectionType.ONLINE;
},
Expand All @@ -57,14 +56,11 @@ function testExecuteEntryTask(callback) {
},
{
taskMenuButton: document.createElement('button'),
fileContextMenu: {
defaultActionMenuItem: document.createElement('div')
}
shareMenuButton: {menu: document.createElement('div')},
fileContextMenu:
{defaultActionMenuItem: document.createElement('div')}
},
new MockMetadataModel({}),
{},
new cr.EventTarget(),
null);
new MockMetadataModel({}), {}, new cr.EventTarget(), null);

controller.executeEntryTask(fileSystem.entries['/test.png']);
reportPromise(new Promise(function(fulfill) {
Expand Down Expand Up @@ -119,6 +115,7 @@ function createTaskController(selectionHandler) {
return new TaskController(
DialogType.FULL_PAGE, {}, {
taskMenuButton: document.createElement('button'),
shareMenuButton: {menu: document.createElement('div')},
fileContextMenu:
{defaultActionMenuItem: document.createElement('div')}
},
Expand Down
Loading

0 comments on commit ef2e848

Please sign in to comment.