Commit f1948150 authored by calamity@chromium.org's avatar calamity@chromium.org

Add tiles to the experimental app list start page.

This CL adds TileItemViews to the experimental app list which currently
show the first 5 apps in the app list. This CL also changes the width
of the placeholder bar on the start page to align with the tiles.

BUG=349727

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273134 0039d316-1c4b-4281-b951-d872f2087c98
parent ca628947
......@@ -138,6 +138,8 @@
'views/speech_view.h',
'views/start_page_view.cc',
'views/start_page_view.h',
'views/tile_item_view.cc',
'views/tile_item_view.h',
'views/top_icon_animation_view.cc',
'views/top_icon_animation_view.h',
],
......
......@@ -234,6 +234,7 @@ void AppListModel::DeleteItem(const std::string& id) {
observers_,
OnAppListItemWillBeDeleted(item));
top_level_item_list_->DeleteItem(id);
FOR_EACH_OBSERVER(AppListModelObserver, observers_, OnAppListItemDeleted());
return;
}
AppListFolderItem* folder = FindFolderItem(item->folder_id());
......@@ -244,6 +245,7 @@ void AppListModel::DeleteItem(const std::string& id) {
observers_,
OnAppListItemWillBeDeleted(item));
child_item.reset(); // Deletes item.
FOR_EACH_OBSERVER(AppListModelObserver, observers_, OnAppListItemDeleted());
}
void AppListModel::NotifyExtensionPreferenceChanged() {
......
......@@ -22,6 +22,9 @@ class APP_LIST_EXPORT AppListModelObserver {
// Triggered just before an item is deleted from the model.
virtual void OnAppListItemWillBeDeleted(AppListItem* item) {}
// Triggered just after an item is deleted from the model.
virtual void OnAppListItemDeleted() {}
// Triggered after |item| has moved, changed folders, or changed properties.
virtual void OnAppListItemUpdated(AppListItem* item) {}
......
......@@ -20,6 +20,7 @@
#include "ui/app_list/views/search_box_view.h"
#include "ui/app_list/views/start_page_view.h"
#include "ui/app_list/views/test/apps_grid_view_test_api.h"
#include "ui/app_list/views/tile_item_view.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/window.h"
#include "ui/views/test/views_test_base.h"
......@@ -43,6 +44,17 @@ bool IsViewAtOrigin(views::View* view) {
return view->bounds().origin().IsOrigin();
}
size_t GetVisibleTileItemViews(const std::vector<TileItemView*>& tiles) {
size_t count = 0;
for (std::vector<TileItemView*>::const_iterator it = tiles.begin();
it != tiles.end();
++it) {
if ((*it)->visible())
count++;
}
return count;
}
// Choose a set that is 3 regular app list pages and 2 landscape app list pages.
const int kInitialItems = 34;
......@@ -248,7 +260,8 @@ void AppListViewTestContext::RunReshowWithOpenFolderTest() {
void AppListViewTestContext::RunStartPageTest() {
EXPECT_FALSE(view_->GetWidget()->IsVisible());
EXPECT_EQ(-1, pagination_model_.total_pages());
delegate_->GetTestModel()->PopulateApps(kInitialItems);
AppListTestModel* model = delegate_->GetTestModel();
model->PopulateApps(3);
Show();
......@@ -267,6 +280,7 @@ void AppListViewTestContext::RunStartPageTest() {
EXPECT_TRUE(IsViewAtOrigin(start_page_view));
EXPECT_FALSE(
IsViewAtOrigin(main_view->contents_view()->apps_container_view()));
EXPECT_EQ(3u, GetVisibleTileItemViews(start_page_view->tile_views()));
main_view->contents_view()->SetShowState(ContentsView::SHOW_APPS);
main_view->contents_view()->Layout();
......@@ -274,6 +288,12 @@ void AppListViewTestContext::RunStartPageTest() {
EXPECT_FALSE(IsViewAtOrigin(start_page_view));
EXPECT_TRUE(
IsViewAtOrigin(main_view->contents_view()->apps_container_view()));
// Check tiles hide and show on deletion and addition.
model->CreateAndAddItem("Test app");
EXPECT_EQ(4u, GetVisibleTileItemViews(start_page_view->tile_views()));
model->DeleteItem(model->GetItemName(0));
EXPECT_EQ(3u, GetVisibleTileItemViews(start_page_view->tile_views()));
} else {
EXPECT_EQ(NULL, start_page_view);
}
......
......@@ -78,10 +78,7 @@ ContentsView::ContentsView(AppListMainView* app_list_main_view,
view_model_->Add(search_results_view, kIndexSearchResults);
if (app_list::switches::IsExperimentalAppListEnabled()) {
content::WebContents* start_page_contents =
view_delegate->GetStartPageContents();
start_page_view_ =
new StartPageView(app_list_main_view, start_page_contents);
start_page_view_ = new StartPageView(app_list_main_view, view_delegate);
AddChildView(start_page_view_);
view_model_->Add(start_page_view_, kIndexStartPage);
}
......
......@@ -4,11 +4,18 @@
#include "ui/app_list/views/start_page_view.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_item.h"
#include "ui/app_list/app_list_model.h"
#include "ui/app_list/app_list_view_delegate.h"
#include "ui/app_list/views/app_list_main_view.h"
#include "ui/app_list/views/tile_item_view.h"
#include "ui/gfx/canvas.h"
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/box_layout.h"
......@@ -16,15 +23,18 @@ namespace app_list {
namespace {
const int kTopMargin = 20;
const int kTopMargin = 30;
const int kWebViewWidth = 200;
const int kWebViewHeight = 95;
const int kWebViewHeight = 105;
const int kInstantContainerSpacing = 15;
const int kBarPlaceholderWidth = 350;
const int kInstantContainerSpacing = 20;
const int kBarPlaceholderWidth = 490;
const int kBarPlaceholderHeight = 30;
const size_t kNumStartPageTiles = 5;
const int kTileSpacing = 10;
// A button that is the placeholder for the search bar in the start page view.
class BarPlaceholderButton : public views::CustomButton {
public:
......@@ -64,14 +74,25 @@ class BarPlaceholderButton : public views::CustomButton {
} // namespace
StartPageView::StartPageView(AppListMainView* app_list_main_view,
content::WebContents* start_page_web_contents)
AppListViewDelegate* view_delegate)
: app_list_main_view_(app_list_main_view),
instant_container_(new views::View) {
AddChildView(instant_container_);
SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
instant_container_->SetLayoutManager(new views::BoxLayout(
model_(NULL),
view_delegate_(view_delegate),
instant_container_(new views::View),
tiles_container_(new views::View) {
SetLayoutManager(new views::BoxLayout(
views::BoxLayout::kVertical, 0, kTopMargin, kInstantContainerSpacing));
// The view containing the start page WebContents and the BarPlaceholder.
AddChildView(instant_container_);
views::BoxLayout* instant_layout_manager = new views::BoxLayout(
views::BoxLayout::kVertical, 0, 0, kInstantContainerSpacing);
instant_layout_manager->set_main_axis_alignment(
views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
instant_container_->SetLayoutManager(instant_layout_manager);
content::WebContents* start_page_web_contents =
view_delegate->GetStartPageContents();
views::WebView* web_view = new views::WebView(
start_page_web_contents ? start_page_web_contents->GetBrowserContext()
: NULL);
......@@ -80,13 +101,50 @@ StartPageView::StartPageView(AppListMainView* app_list_main_view,
instant_container_->AddChildView(web_view);
instant_container_->AddChildView(new BarPlaceholderButton(this));
// The view containing the start page tiles.
AddChildView(tiles_container_);
views::BoxLayout* tiles_layout_manager =
new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, kTileSpacing);
tiles_layout_manager->set_main_axis_alignment(
views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
tiles_container_->SetLayoutManager(tiles_layout_manager);
for (size_t i = 0; i < kNumStartPageTiles; ++i) {
TileItemView* tile_item = new TileItemView();
tiles_container_->AddChildView(tile_item);
tile_views_.push_back(tile_item);
}
SetModel(view_delegate_->GetModel());
view_delegate_->AddObserver(this);
}
StartPageView::~StartPageView() {
view_delegate_->RemoveObserver(this);
}
void StartPageView::SetModel(AppListModel* model) {
DCHECK(model);
if (model_)
model_->RemoveObserver(this);
model_ = model;
model_->AddObserver(this);
Reset();
}
void StartPageView::Reset() {
instant_container_->SetVisible(true);
if (!model_ || !model_->top_level_item_list())
return;
for (size_t i = 0; i < kNumStartPageTiles; ++i) {
AppListItem* item = NULL;
if (i < model_->top_level_item_list()->item_count())
item = model_->top_level_item_list()->item_at(i);
tile_views_[i]->SetAppListItem(item);
}
Layout();
}
void StartPageView::ButtonPressed(views::Button* sender,
......@@ -95,4 +153,24 @@ void StartPageView::ButtonPressed(views::Button* sender,
instant_container_->SetVisible(false);
}
void StartPageView::OnProfilesChanged() {
SetModel(view_delegate_->GetModel());
}
void StartPageView::OnAppListModelStatusChanged() {
Reset();
}
void StartPageView::OnAppListItemAdded(AppListItem* item) {
Reset();
}
void StartPageView::OnAppListItemDeleted() {
Reset();
}
void StartPageView::OnAppListItemUpdated(AppListItem* item) {
Reset();
}
} // namespace app_list
......@@ -6,6 +6,8 @@
#define UI_APP_LIST_VIEWS_START_PAGE_VIEW_H_
#include "base/basictypes.h"
#include "ui/app_list/app_list_model_observer.h"
#include "ui/app_list/app_list_view_delegate_observer.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/view.h"
......@@ -16,25 +18,51 @@ class WebContents;
namespace app_list {
class AppListMainView;
class AppListModel;
class AppListViewDelegate;
class TileItemView;
// The start page for the experimental app list.
class StartPageView : public views::View, public views::ButtonListener {
class StartPageView : public views::View,
public views::ButtonListener,
public AppListViewDelegateObserver,
public AppListModelObserver {
public:
StartPageView(AppListMainView* app_list_main_view,
content::WebContents* start_page_web_contents);
AppListViewDelegate* view_delegate);
virtual ~StartPageView();
void Reset();
const std::vector<TileItemView*>& tile_views() const { return tile_views_; }
private:
void SetModel(AppListModel* model);
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
// Overridden from AppListViewDelegateObserver:
virtual void OnProfilesChanged() OVERRIDE;
// Overridden from AppListModelObserver:
virtual void OnAppListModelStatusChanged() OVERRIDE;
virtual void OnAppListItemAdded(AppListItem* item) OVERRIDE;
virtual void OnAppListItemDeleted() OVERRIDE;
virtual void OnAppListItemUpdated(AppListItem* item) OVERRIDE;
// The parent view of ContentsView which is the parent of this view.
AppListMainView* app_list_main_view_;
AppListModel* model_; // Owned by AppListSyncableService.
AppListViewDelegate* view_delegate_; // Owned by AppListView.
views::View* instant_container_; // Owned by views hierarchy.
views::View* tiles_container_; // Owned by views hierarchy.
std::vector<TileItemView*> tile_views_;
DISALLOW_COPY_AND_ASSIGN(StartPageView);
};
......
// Copyright 2014 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.
#include "ui/app_list/views/tile_item_view.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_item.h"
#include "ui/app_list/app_list_model.h"
#include "ui/app_list/app_list_view_delegate.h"
#include "ui/app_list/views/app_list_main_view.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_utils.h"
#include "ui/views/background.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
namespace {
const int kTileSize = 90;
const int kTileHorizontalPadding = 10;
const int kTileImageSize = 48;
const SkColor kTileBackgroundColor = SK_ColorWHITE;
const SkColor kTileBorderColor = SkColorSetARGB(0x30, 0xD0, 0xD0, 0xD0);
const int kTileColorStripHeight = 2;
const SkAlpha kTileColorStripOpacity = 0X5F;
const int kTileCornerRadius = 2;
} // namespace
namespace app_list {
// A background for the start page item view which consists of a rounded rect
// with a dominant color strip at the bottom.
class TileItemView::TileItemBackground : public views::Background {
public:
TileItemBackground() : strip_color_(SK_ColorBLACK) {}
virtual ~TileItemBackground() {}
void set_strip_color(SkColor strip_color) { strip_color_ = strip_color; }
// Overridden from views::Background:
virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
SkPaint paint;
paint.setFlags(SkPaint::kAntiAlias_Flag);
// Paint the border.
paint.setColor(kTileBorderColor);
canvas->DrawRoundRect(view->GetContentsBounds(), kTileCornerRadius, paint);
// Paint a rectangle for the color strip.
gfx::Rect color_strip_rect(view->GetContentsBounds());
color_strip_rect.Inset(1, 1, 1, 1);
paint.setColor(SkColorSetA(strip_color_, kTileColorStripOpacity));
canvas->DrawRoundRect(color_strip_rect, kTileCornerRadius, paint);
// Paint the main background rectangle, leaving part of the color strip
// unobscured.
gfx::Rect static_background_rect(color_strip_rect);
static_background_rect.Inset(0, 0, 0, kTileColorStripHeight);
paint.setColor(kTileBackgroundColor);
canvas->DrawRoundRect(static_background_rect, kTileCornerRadius, paint);
}
private:
SkColor strip_color_;
DISALLOW_COPY_AND_ASSIGN(TileItemBackground);
};
TileItemView::TileItemView()
: views::CustomButton(this),
item_(NULL),
icon_(new views::ImageView),
title_(new views::Label),
background_(new TileItemBackground()) {
set_background(background_);
views::BoxLayout* layout_manager = new views::BoxLayout(
views::BoxLayout::kVertical, kTileHorizontalPadding, 0, 0);
layout_manager->set_main_axis_alignment(
views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
SetLayoutManager(layout_manager);
icon_->SetImageSize(gfx::Size(kTileImageSize, kTileImageSize));
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
title_->SetAutoColorReadabilityEnabled(false);
title_->SetEnabledColor(kGridTitleColor);
title_->SetFontList(rb.GetFontList(kItemTextFontStyle));
title_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
AddChildView(icon_);
AddChildView(title_);
}
TileItemView::~TileItemView() {
}
void TileItemView::SetAppListItem(AppListItem* item) {
item_ = item;
if (!item) {
SetVisible(false);
icon_->SetImage(NULL);
title_->SetText(base::string16());
return;
}
SetVisible(true);
icon_->SetImage(item_->icon());
title_->SetText(base::UTF8ToUTF16(item_->name()));
background_->set_strip_color(
color_utils::CalculateKMeanColorOfBitmap(*item_->icon().bitmap()));
}
gfx::Size TileItemView::GetPreferredSize() const {
return gfx::Size(kTileSize, kTileSize);
}
void TileItemView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
item_->Activate(event.flags());
}
} // namespace app_list
\ No newline at end of file
// Copyright 2014 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 UI_APP_LIST_VIEWS_TILE_ITEM_VIEW_H_
#define UI_APP_LIST_VIEWS_TILE_ITEM_VIEW_H_
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/custom_button.h"
namespace views {
class ImageView;
class Label;
}
namespace app_list {
class AppListItem;
// The view for a tile in the app list on the start/search page.
class TileItemView : public views::CustomButton, public views::ButtonListener {
public:
TileItemView();
virtual ~TileItemView();
void SetAppListItem(AppListItem* item);
private:
class TileItemBackground;
// Overridden from views::View:
virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
// Owned by the model provided by the AppListViewDelegate.
AppListItem* item_;
views::ImageView* icon_; // Owned by views hierarchy.
views::Label* title_; // Owned by views hierarchy.
TileItemBackground* background_;
DISALLOW_COPY_AND_ASSIGN(TileItemView);
};
} // namespace app_list
#endif // UI_APP_LIST_VIEWS_TILE_ITEM_VIEW_H_
\ No newline at end of file
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