Commit 9aef60e2 authored by xiyuan@chromium.org's avatar xiyuan@chromium.org

[Aura] Polish app list.

- Remove search box until we have decided how to approach it;
- Show apps pagination dots;
- Dismiss app list UI on escape or click on non-app and non nav dots;
- Defer widget showing further until apps are loaded by webui;
- Add a container div to limit apps page height so that the gap between apps icons and nav dots are not too big;
- Passing bounds when requesting app list widget to avoid resizing;

BUG=98308,105794,106451
TEST=Verify search box is gone, nav gots show up on bottom and could switch pages by clicking on it;


Review URL: http://codereview.chromium.org/8747021

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113156 0039d316-1c4b-4281-b951-d872f2087c98
parent 086bc9a3
......@@ -17,42 +17,42 @@ body {
padding: 0;
}
.tile-page-scrollbar {
background-color: #7f7f7f;
}
.app-contents > span {
color: white;
font-size: 14px;
font-weight: bold;
padding: 2px; /* Extra padding for text-shadow. */
text-shadow: 0 0 2px black, 0 0 4px black;
}
#launcher-search-container {
position: relative;
z-index: 5;
}
#launcher-search,
#launcher-search::-webkit-input-placeholder {
color: white;
}
#launcher-search {
-webkit-padding-start: 10px;
-webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1);
background-color: rgba(0, 0, 0, 0.2);
border: none;
font-size: 14px;
height: 34px;
min-width: 384px;
outline: 1px solid rgba(0, 0, 0, 0.1);
/*
* #container is used to host apps page in a fixed 900x550 area so that
* we don't have excessive space between app icons and nav dots. #container
* is center aligned with its parent. We use top:50% and left:50% to move it
* to parent's center and use negative margin-top and margin-left to align its
* center with parent's center. Because of this, margin-top must be half of
* the height and margin-left must be half of the width.
*/
#container {
height: 550px;
left: 50%;
margin-top: -225px;
margin-left: -450px;
position: absolute;
top: 50%;
width: 900px;
}
#card-slider-frame {
/* Must match #footer height. 0 because footer is hidden.*/
bottom: 0;
/* Must match #footer height. */
bottom: 50px;
overflow: hidden;
/* We want this to fill the window except for the region used
by footer */
position: fixed;
top: 0;
position: absolute;
height: 500px;
width: 100%;
}
......@@ -63,10 +63,9 @@ body {
}
#footer {
background-image: -webkit-linear-gradient(
rgba(242, 242, 242, 0.9), rgba(222, 222, 222, 0.9));
background: transparent;
bottom: 0;
position: fixed;
position: absolute;
width: 100%;
z-index: 5;
}
......@@ -76,3 +75,30 @@ body {
display: -webkit-box;
height: 49px;
}
.dot .selection-bar {
border-color: #7f7f7f;
opacity: 0.2;
}
.dot input {
color: #7f7f7f;
font-size: 12px;
}
.dot:focus input,
.dot:hover input,
.dot.selected input {
color: white;
}
.dot:focus .selection-bar,
.dot:hover .selection-bar,
.dot.drag-target .selection-bar {
border-color: #b2b2b2;
opacity: 1;
}
.dot.selected .selection-bar {
opacity: 1;
}
......@@ -33,30 +33,19 @@
</head>
<body>
<div id="launcher-search-container">
<input id="launcher-search" type="text"
i18n-values="placeholder:search-box-hint">
</div>
<div id="card-slider-frame">
<div id="page-list"></div>
</div>
</body>
<!-- Invisible yet maybe needed in the future elements -->
<div id="invisible" hidden>
<div id="footer">
<div id="footer-border"></div>
<div id="footer-content">
<ul id="dot-list">
</ul>
<div id="trash">
<span i18n-content="appuninstall"></span>
<div id="container">
<div id="card-slider-frame">
<div id="page-list"></div>
</div>
<div id="footer">
<div id="footer-border"></div>
<div id="footer-content">
<ul id="dot-list">
</ul>
</div>
</div>
</div>
</div>
</body>
<!-- Apps promo. -->
<div id="apps-promo-extras-template" class="apps-promo-extras" hidden>
......
......@@ -23,6 +23,21 @@ cr.define('appList', function() {
*/
function load() {
appsView = new appList.AppsView();
document.addEventListener('click', onDocClick);
}
/**
* Document click event handler.
*/
function onDocClick(e) {
// Close if click is on body, or not on app, paging dot or its children.
if (e.target == document.body ||
(!e.target.classList.contains('app') &&
!e.target.classList.contains('dot') &&
!findAncestorByClass(e.target, 'dot'))) {
chrome.send('close');
}
}
/**
......@@ -46,6 +61,7 @@ cr.define('appList', function() {
function getAppsCallback(data) {
appsView.getAppsCallback(data);
chrome.send('onAppsLoaded');
}
function getAppsPageIndex(page) {
......
......@@ -6,17 +6,21 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/browser/ui/webui/aura/app_list_ui.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_widget_host_view.h"
#include "ui/aura_shell/shell.h"
#include "ui/views/widget/widget.h"
AppListWindow::AppListWindow(
AppListWindow::AppListWindow(const gfx::Rect& bounds,
const aura_shell::ShellDelegate::SetWidgetCallback& callback)
: widget_(NULL),
contents_(NULL),
callback_(callback) {
Init();
callback_(callback),
content_rendered_(false),
apps_loaded_(false) {
Init(bounds);
}
AppListWindow::~AppListWindow() {
......@@ -26,7 +30,7 @@ void AppListWindow::DeleteDelegate() {
delete this;
}
views::View* AppListWindow::GetContentsView() {
views::View* AppListWindow::GetInitiallyFocusedView() {
return contents_;
}
......@@ -38,6 +42,30 @@ const views::Widget* AppListWindow::GetWidget() const {
return widget_;
}
bool AppListWindow::HandleContextMenu(const ContextMenuParams& params) {
// Do not show the context menu for non-debug build.
#if !defined(NDEBUG)
return false;
#else
return true;
#endif
}
void AppListWindow::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
if (event.windowsKeyCode == ui::VKEY_ESCAPE)
Close();
}
bool AppListWindow::TakeFocus(bool reverse) {
// Forward the focus back to web contents.
contents_->dom_contents()->tab_contents()->FocusThroughTabTraversal(reverse);
return true;
}
bool AppListWindow::IsPopupOrPanel(const TabContents* source) const {
return true;
}
void AppListWindow::OnRenderHostCreated(RenderViewHost* host) {
}
......@@ -45,10 +73,21 @@ void AppListWindow::OnTabMainFrameLoaded() {
}
void AppListWindow::OnTabMainFrameFirstRender() {
callback_.Run(widget_);
content_rendered_ = true;
SetWidgetIfReady();
}
void AppListWindow::Close() {
// We should be visible when running here and toggle actually closes us.
aura_shell::Shell::GetInstance()->ToggleAppList();
}
void AppListWindow::Init() {
void AppListWindow::OnAppsLoaded() {
apps_loaded_ = true;
SetWidgetIfReady();
}
void AppListWindow::Init(const gfx::Rect& bounds) {
DCHECK(!widget_ && !contents_);
contents_ = new DOMView();
......@@ -56,8 +95,10 @@ void AppListWindow::Init() {
TabContents* tab = contents_->dom_contents()->tab_contents();
tab_watcher_.reset(new TabFirstRenderWatcher(tab, this));
tab->set_delegate(this);
contents_->LoadURL(GURL(chrome::kChromeUIAppListURL));
static_cast<AppListUI*>(tab->web_ui())->set_delegate(this);
// Use a background with transparency to trigger transparent webkit.
SkBitmap background;
......@@ -70,10 +111,7 @@ void AppListWindow::Init() {
views::Widget::InitParams widget_params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
// A non-empty bounds so that we get rendered notification. Make the size
// close the final size so that card slider resize handler does no generate
// unexpected animation.
widget_params.bounds = gfx::Rect(0, 0, 900, 700);
widget_params.bounds = bounds;
widget_params.delegate = this;
widget_params.keep_on_top = true;
widget_params.transparent = true;
......@@ -82,3 +120,8 @@ void AppListWindow::Init() {
widget_->Init(widget_params);
widget_->SetContentsView(contents_);
}
void AppListWindow::SetWidgetIfReady() {
if (content_rendered_ && apps_loaded_)
callback_.Run(widget_);
}
......@@ -8,6 +8,8 @@
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/tab_first_render_watcher.h"
#include "chrome/browser/ui/webui/aura/app_list_ui_delegate.h"
#include "content/browser/tab_contents/tab_contents_delegate.h"
#include "ui/aura_shell/shell_delegate.h"
#include "ui/views/widget/widget_delegate.h"
......@@ -18,9 +20,12 @@ class Widget;
}
class AppListWindow : public views::WidgetDelegate,
public TabFirstRenderWatcher::Delegate {
public TabContentsDelegate,
public TabFirstRenderWatcher::Delegate,
public AppListUIDelegate {
public:
explicit AppListWindow(
AppListWindow(
const gfx::Rect& bounds,
const aura_shell::ShellDelegate::SetWidgetCallback& callback);
private:
......@@ -28,17 +33,31 @@ class AppListWindow : public views::WidgetDelegate,
// views::WidgetDelegate overrides:
virtual void DeleteDelegate() OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
virtual views::Widget* GetWidget() OVERRIDE;
virtual const views::Widget* GetWidget() const OVERRIDE;
// TabContentsDelegate implementation:
virtual bool HandleContextMenu(const ContextMenuParams& params) OVERRIDE;
virtual void HandleKeyboardEvent(
const NativeWebKeyboardEvent& event) OVERRIDE;
virtual bool IsPopupOrPanel(const TabContents* source) const OVERRIDE;
virtual bool TakeFocus(bool reverse) OVERRIDE;
// TabFirstRenderWatcher::Delegate implementation:
virtual void OnRenderHostCreated(RenderViewHost* host) OVERRIDE;
virtual void OnTabMainFrameLoaded() OVERRIDE;
virtual void OnTabMainFrameFirstRender() OVERRIDE;
// AppListUIDelegate implementation:
virtual void Close() OVERRIDE;
virtual void OnAppsLoaded() OVERRIDE;
// Initializes the window.
void Init();
void Init(const gfx::Rect& bounds);
// Check and fire set widget callback if we are ready.
void SetWidgetIfReady();
views::Widget* widget_;
DOMView* contents_;
......@@ -49,6 +68,12 @@ class AppListWindow : public views::WidgetDelegate,
// Callback to set app list widget when it's ready.
aura_shell::ShellDelegate::SetWidgetCallback callback_;
// True if webui is rendered.
bool content_rendered_;
// True if apps info is loaded by webui.
bool apps_loaded_;
DISALLOW_COPY_AND_ASSIGN(AppListWindow);
};
......
......@@ -58,8 +58,10 @@ views::Widget* ChromeShellDelegate::CreateStatusArea() {
}
void ChromeShellDelegate::RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) {
new AppListWindow(callback); // AppListWindow deletes itself when closed.
// AppListWindow deletes itself when closed.
new AppListWindow(bounds, callback);
}
void ChromeShellDelegate::LauncherItemClicked(
......
......@@ -38,7 +38,9 @@ class ChromeShellDelegate : public aura_shell::ShellDelegate {
// aura_shell::ShellDelegate overrides;
virtual void CreateNewWindow() OVERRIDE;
virtual views::Widget* CreateStatusArea() OVERRIDE;
virtual void RequestAppListWidget(const SetWidgetCallback& callback) OVERRIDE;
virtual void RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) OVERRIDE;
virtual void LauncherItemClicked(
const aura_shell::LauncherItem& item) OVERRIDE;
virtual bool ConfigureLauncherItem(aura_shell::LauncherItem* item) OVERRIDE;
......
......@@ -9,6 +9,7 @@
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/browser/ui/webui/aura/app_list_ui_delegate.h"
#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
......@@ -76,10 +77,49 @@ ChromeWebUIDataSource* CreateAppListUIHTMLSource(PrefService* prefs) {
return source;
}
class AppListHandler : public WebUIMessageHandler {
public:
AppListHandler() {}
virtual ~AppListHandler() {}
// WebUIMessageHandler
virtual void RegisterMessages() OVERRIDE;
private:
AppListUI* app_list_ui() const {
return static_cast<AppListUI*>(web_ui_);
}
void HandleClose(const base::ListValue* args);
void HandleAppsLoaded(const base::ListValue* args);
DISALLOW_COPY_AND_ASSIGN(AppListHandler);
};
void AppListHandler::RegisterMessages() {
web_ui_->RegisterMessageCallback("close",
base::Bind(&AppListHandler::HandleClose, base::Unretained(this)));
web_ui_->RegisterMessageCallback("onAppsLoaded",
base::Bind(&AppListHandler::HandleAppsLoaded, base::Unretained(this)));
}
void AppListHandler::HandleClose(const base::ListValue* args) {
if (app_list_ui()->delegate())
app_list_ui()->delegate()->Close();
}
void AppListHandler::HandleAppsLoaded(const base::ListValue* args) {
if (app_list_ui()->delegate())
app_list_ui()->delegate()->OnAppsLoaded();
}
} // namespace
AppListUI::AppListUI(TabContents* contents)
: ChromeWebUI(contents) {
: ChromeWebUI(contents),
delegate_(NULL) {
AddMessageHandler((new AppListHandler)->Attach(this));
ExtensionService* service = GetProfile()->GetExtensionService();
if (service)
AddMessageHandler((new AppLauncherHandler(service))->Attach(this));
......
......@@ -8,11 +8,23 @@
#include "chrome/browser/ui/webui/chrome_web_ui.h"
class AppListUIDelegate;
class AppListUI : public ChromeWebUI {
public:
explicit AppListUI(TabContents* contents);
AppListUIDelegate* delegate() const {
return delegate_;
}
void set_delegate(AppListUIDelegate* delegate) {
delegate_ = delegate;
}
private:
AppListUIDelegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(AppListUI);
};
......
// Copyright (c) 2011 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.
#ifndef CHROME_BROWSER_UI_WEBUI_AURA_APP_LIST_UI_DELEGATE_H_
#define CHROME_BROWSER_UI_WEBUI_AURA_APP_LIST_UI_DELEGATE_H_
#pragma once
class AppListUIDelegate {
public:
// Close AppListUI.
virtual void Close() = 0;
// Invoked when apps are loaded.
virtual void OnAppsLoaded() = 0;
};
#endif // CHROME_BROWSER_UI_WEBUI_AURA_APP_LIST_UI_DELEGATE_H_
......@@ -3642,6 +3642,7 @@
'browser/ui/webui/about_ui.h',
'browser/ui/webui/active_downloads_ui.cc',
'browser/ui/webui/active_downloads_ui.h',
'browser/ui/webui/aura/app_list_ui_delegate.h',
'browser/ui/webui/aura/app_list_ui.cc',
'browser/ui/webui/aura/app_list_ui.h',
'browser/ui/webui/bookmark_all_tabs_dialog.cc',
......
......@@ -62,6 +62,7 @@ void AppList::SetVisible(bool visible) {
ScheduleAnimation();
} else if (is_visible_ && !set_widget_factory_.HasWeakPtrs()) {
Shell::GetInstance()->delegate()->RequestAppListWidget(
GetPreferredBounds(false),
base::Bind(&AppList::SetWidget, set_widget_factory_.GetWeakPtr()));
}
}
......@@ -88,7 +89,6 @@ void AppList::SetWidget(views::Widget* widget) {
ScheduleAnimation();
widget_->Show();
widget_->Activate();
} else {
widget->Close();
}
......@@ -162,6 +162,8 @@ void AppList::OnLayerAnimationScheduled(
void AppList::OnWidgetClosing(views::Widget* widget) {
DCHECK(widget_ == widget);
if (is_visible_)
SetVisible(false);
ResetWidget();
}
......
......@@ -28,11 +28,12 @@ class AppListWindow : public views::WidgetDelegateView {
}
// static
static views::Widget* Create() {
static views::Widget* Create(const gfx::Rect& bounds) {
AppListWindow* app_list = new AppListWindow;
views::Widget::InitParams widget_params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
widget_params.bounds = bounds;
widget_params.delegate = app_list;
widget_params.keep_on_top = true;
widget_params.transparent = true;
......@@ -66,8 +67,9 @@ class ShellDelegateImpl : public aura_shell::ShellDelegate {
}
virtual void RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) OVERRIDE {
callback.Run(AppListWindow::Create());
callback.Run(AppListWindow::Create(bounds));
}
virtual void LauncherItemClicked(
......
......@@ -9,6 +9,10 @@
#include "base/callback.h"
#include "ui/aura_shell/aura_shell_export.h"
namespace gfx {
class Rect;
}
namespace views {
class Widget;
}
......@@ -35,7 +39,9 @@ class AURA_SHELL_EXPORT ShellDelegate {
// Invoked to create app list widget. The Delegate calls the callback
// when the widget is ready to show.
virtual void RequestAppListWidget(const SetWidgetCallback& callback) = 0;
virtual void RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) = 0;
// Invoked when the user clicks on a window entry in the launcher.
virtual void LauncherItemClicked(const LauncherItem& item) = 0;
......
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