Commit e2bd02ff authored by Weidong Guo's avatar Weidong Guo Committed by Commit Bot

Add SearchResultSuggestionChipView for homecher

In homecher, suggestion chips will replace suggested apps.
1. Modify SuggestionChipView to alter between assistant style and app
   list style based on input parameter.
2. Add the SearchResultSuggestionChipView which contains a
   SuggestionChipView.
3. Add the SuggestionChipContainerView to contain a list of suggestion
chips.

Bug: 855282
Change-Id: I3ee78198aafa5c480f97ee3d3bf9a6aa70504e20
Reviewed-on: https://chromium-review.googlesource.com/1112436
Commit-Queue: Weidong Guo <weidongg@chromium.org>
Reviewed-by: default avatarYury Khmel <khmel@chromium.org>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571178}
parent 26977a4c
...@@ -78,12 +78,16 @@ component("app_list") { ...@@ -78,12 +78,16 @@ component("app_list") {
"views/search_result_list_view.h", "views/search_result_list_view.h",
"views/search_result_page_view.cc", "views/search_result_page_view.cc",
"views/search_result_page_view.h", "views/search_result_page_view.h",
"views/search_result_suggestion_chip_view.cc",
"views/search_result_suggestion_chip_view.h",
"views/search_result_tile_item_list_view.cc", "views/search_result_tile_item_list_view.cc",
"views/search_result_tile_item_list_view.h", "views/search_result_tile_item_list_view.h",
"views/search_result_tile_item_view.cc", "views/search_result_tile_item_view.cc",
"views/search_result_tile_item_view.h", "views/search_result_tile_item_view.h",
"views/search_result_view.cc", "views/search_result_view.cc",
"views/search_result_view.h", "views/search_result_view.h",
"views/suggestion_chip_container_view.cc",
"views/suggestion_chip_container_view.h",
"views/suggestion_chip_view.cc", "views/suggestion_chip_view.cc",
"views/suggestion_chip_view.h", "views/suggestion_chip_view.h",
"views/suggestions_container_view.cc", "views/suggestions_container_view.cc",
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "ash/app_list/views/horizontal_page_container.h" #include "ash/app_list/views/horizontal_page_container.h"
#include "ash/app_list/views/page_switcher.h" #include "ash/app_list/views/page_switcher.h"
#include "ash/app_list/views/search_box_view.h" #include "ash/app_list/views/search_box_view.h"
#include "ash/app_list/views/suggestion_chip_container_view.h"
#include "ash/app_list/views/suggestions_container_view.h" #include "ash/app_list/views/suggestions_container_view.h"
#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/app_list/app_list_features.h"
#include "ash/public/cpp/app_list/app_list_switches.h" #include "ash/public/cpp/app_list/app_list_switches.h"
...@@ -38,9 +39,18 @@ constexpr int kSearchBoxPeekingTopPadding = 24; ...@@ -38,9 +39,18 @@ constexpr int kSearchBoxPeekingTopPadding = 24;
// Minimum top padding of search box in fullscreen state. // Minimum top padding of search box in fullscreen state.
constexpr int kSearchBoxMinimumTopPadding = 24; constexpr int kSearchBoxMinimumTopPadding = 24;
// Height of suggestion chip container.
constexpr int kSuggestionChipContainerHeight = 32;
AppsContainerView::AppsContainerView(ContentsView* contents_view, AppsContainerView::AppsContainerView(ContentsView* contents_view,
AppListModel* model) AppListModel* model)
: contents_view_(contents_view) { : contents_view_(contents_view) {
if (features::IsNewStyleLauncherEnabled()) {
suggestion_chip_container_view_ =
new SuggestionChipContainerView(contents_view);
AddChildView(suggestion_chip_container_view_);
UpdateSuggestionChips();
}
apps_grid_view_ = new AppsGridView(contents_view_, nullptr); apps_grid_view_ = new AppsGridView(contents_view_, nullptr);
apps_grid_view_->SetLayout(kPreferredCols, kPreferredRows); apps_grid_view_->SetLayout(kPreferredCols, kPreferredRows);
AddChildView(apps_grid_view_); AddChildView(apps_grid_view_);
...@@ -164,6 +174,13 @@ void AppsContainerView::Layout() { ...@@ -164,6 +174,13 @@ void AppsContainerView::Layout() {
switch (show_state_) { switch (show_state_) {
case SHOW_APPS: { case SHOW_APPS: {
if (suggestion_chip_container_view_) {
gfx::Rect chip_container_rect(rect);
chip_container_rect.set_height(kSuggestionChipContainerHeight);
suggestion_chip_container_view_->SetBoundsRect(chip_container_rect);
rect.Inset(0, kSuggestionChipContainerHeight, 0, 0);
}
gfx::Rect grid_rect = rect; gfx::Rect grid_rect = rect;
grid_rect.Inset(kAppsGridLeftRightPadding, 0); grid_rect.Inset(kAppsGridLeftRightPadding, 0);
apps_grid_view_->SetBoundsRect(grid_rect); apps_grid_view_->SetBoundsRect(grid_rect);
...@@ -389,4 +406,13 @@ void AppsContainerView::SetShowState(ShowState show_state, ...@@ -389,4 +406,13 @@ void AppsContainerView::SetShowState(ShowState show_state,
} }
} }
void AppsContainerView::UpdateSuggestionChips() {
DCHECK(suggestion_chip_container_view_);
suggestion_chip_container_view_->SetResults(
contents_view_->GetAppListMainView()
->view_delegate()
->GetSearchModel()
->results());
}
} // namespace app_list } // namespace app_list
...@@ -23,6 +23,7 @@ class AppListModel; ...@@ -23,6 +23,7 @@ class AppListModel;
class ContentsView; class ContentsView;
class FolderBackgroundView; class FolderBackgroundView;
class PageSwitcher; class PageSwitcher;
class SuggestionChipContainerView;
// AppsContainerView contains a root level AppsGridView to render the root level // AppsContainerView contains a root level AppsGridView to render the root level
// app items, and a AppListFolderView to render the app items inside the // app items, and a AppListFolderView to render the app items inside the
...@@ -108,9 +109,13 @@ class APP_LIST_EXPORT AppsContainerView : public HorizontalPage { ...@@ -108,9 +109,13 @@ class APP_LIST_EXPORT AppsContainerView : public HorizontalPage {
// Returns the bounds of the page in the parent view during dragging. // Returns the bounds of the page in the parent view during dragging.
gfx::Rect GetPageBoundsDuringDragging(ash::AppListState state) const; gfx::Rect GetPageBoundsDuringDragging(ash::AppListState state) const;
// Updates suggestion chips from app list model.
void UpdateSuggestionChips();
ContentsView* contents_view_; // Not owned. ContentsView* contents_view_; // Not owned.
// The views below are owned by views hierarchy. // The views below are owned by views hierarchy.
SuggestionChipContainerView* suggestion_chip_container_view_ = nullptr;
AppsGridView* apps_grid_view_ = nullptr; AppsGridView* apps_grid_view_ = nullptr;
AppListFolderView* app_list_folder_view_ = nullptr; AppListFolderView* app_list_folder_view_ = nullptr;
PageSwitcher* page_switcher_ = nullptr; PageSwitcher* page_switcher_ = nullptr;
......
...@@ -314,10 +314,14 @@ AppsGridView::AppsGridView(ContentsView* contents_view, ...@@ -314,10 +314,14 @@ AppsGridView::AppsGridView(ContentsView* contents_view,
layer()->SetFillsBoundsOpaquely(false); layer()->SetFillsBoundsOpaquely(false);
if (!folder_delegate_) { if (!folder_delegate_) {
suggestions_container_ = // Suggestions container is replaced with suggestion chip container if new
new SuggestionsContainerView(contents_view_, &pagination_model_); // style launcher is enabled.
AddChildView(suggestions_container_); if (!features::IsNewStyleLauncherEnabled()) {
UpdateSuggestions(); suggestions_container_ =
new SuggestionsContainerView(contents_view_, &pagination_model_);
AddChildView(suggestions_container_);
UpdateSuggestions();
}
all_apps_indicator_ = new IndicatorChipView( all_apps_indicator_ = new IndicatorChipView(
l10n_util::GetStringUTF16(IDS_ALL_APPS_INDICATOR)); l10n_util::GetStringUTF16(IDS_ALL_APPS_INDICATOR));
...@@ -409,8 +413,10 @@ void AppsGridView::ResetForShowApps() { ...@@ -409,8 +413,10 @@ void AppsGridView::ResetForShowApps() {
} }
void AppsGridView::DisableFocusForShowingActiveFolder(bool disabled) { void AppsGridView::DisableFocusForShowingActiveFolder(bool disabled) {
for (auto* v : suggestions_container_->tile_views()) if (suggestions_container_) {
v->SetEnabled(!disabled); for (auto* v : suggestions_container_->tile_views())
v->SetEnabled(!disabled);
}
for (int i = 0; i < view_model_.view_size(); ++i) { for (int i = 0; i < view_model_.view_size(); ++i) {
view_model_.view_at(i)->SetEnabled(!disabled); view_model_.view_at(i)->SetEnabled(!disabled);
} }
...@@ -2487,9 +2493,12 @@ int AppsGridView::GetHeightOnTopOfAllAppsTiles(int page) const { ...@@ -2487,9 +2493,12 @@ int AppsGridView::GetHeightOnTopOfAllAppsTiles(int page) const {
return 0; return 0;
if (page == 0) { if (page == 0) {
DCHECK(suggestions_container_ && all_apps_indicator_); const int suggestions_container_height =
return kSearchBoxBottomPadding + suggestions_container_
suggestions_container_->GetPreferredSize().height() + ? suggestions_container_->GetPreferredSize().height()
: 0;
DCHECK(all_apps_indicator_);
return kSearchBoxBottomPadding + suggestions_container_height +
kSuggestionsAllAppsIndicatorPadding + kSuggestionsAllAppsIndicatorPadding +
all_apps_indicator_->GetPreferredSize().height() + all_apps_indicator_->GetPreferredSize().height() +
kAllAppsIndicatorBottomPadding; kAllAppsIndicatorBottomPadding;
......
...@@ -52,6 +52,15 @@ bool SearchResultContainerView::IsValidSelectionIndex(int index) const { ...@@ -52,6 +52,15 @@ bool SearchResultContainerView::IsValidSelectionIndex(int index) const {
return index >= 0 && index <= num_results() - 1; return index >= 0 && index <= num_results() - 1;
} }
void SearchResultContainerView::NotifyFirstResultYIndex(int /*y_index*/) {
NOTREACHED();
}
int SearchResultContainerView::GetYSize() {
NOTREACHED();
return 0;
}
void SearchResultContainerView::Update() { void SearchResultContainerView::Update() {
update_factory_.InvalidateWeakPtrs(); update_factory_.InvalidateWeakPtrs();
num_results_ = DoUpdate(); num_results_ = DoUpdate();
...@@ -68,23 +77,40 @@ const char* SearchResultContainerView::GetClassName() const { ...@@ -68,23 +77,40 @@ const char* SearchResultContainerView::GetClassName() const {
return "SearchResultContainerView"; return "SearchResultContainerView";
} }
void SearchResultContainerView::ListItemsAdded(size_t start, size_t count) { void SearchResultContainerView::ListItemsAdded(size_t /*start*/,
size_t /*count*/) {
ScheduleUpdate(); ScheduleUpdate();
} }
void SearchResultContainerView::ListItemsRemoved(size_t start, size_t count) { void SearchResultContainerView::ListItemsRemoved(size_t /*start*/,
size_t /*count*/) {
ScheduleUpdate(); ScheduleUpdate();
} }
void SearchResultContainerView::ListItemMoved(size_t index, void SearchResultContainerView::ListItemMoved(size_t /*index*/,
size_t target_index) { size_t /*target_index*/) {
ScheduleUpdate(); ScheduleUpdate();
} }
void SearchResultContainerView::ListItemsChanged(size_t start, size_t count) { void SearchResultContainerView::ListItemsChanged(size_t /*start*/,
size_t /*count*/) {
ScheduleUpdate(); ScheduleUpdate();
} }
void SearchResultContainerView::OnContainerSelected(
bool /*from_bottom*/,
bool /*directional_movement*/) {
NOTREACHED();
}
views::View* SearchResultContainerView::GetSelectedView() {
return nullptr;
}
SearchResultBaseView* SearchResultContainerView::GetFirstResultView() {
return nullptr;
}
void SearchResultContainerView::ScheduleUpdate() { void SearchResultContainerView::ScheduleUpdate() {
// When search results are added one by one, each addition generates an update // When search results are added one by one, each addition generates an update
// request. Consolidates those update requests into one Update call. // request. Consolidates those update requests into one Update call.
...@@ -95,4 +121,7 @@ void SearchResultContainerView::ScheduleUpdate() { ...@@ -95,4 +121,7 @@ void SearchResultContainerView::ScheduleUpdate() {
} }
} }
void SearchResultContainerView::UpdateSelectedIndex(int /*old_selected*/,
int /*new_selected*/) {}
} // namespace app_list } // namespace app_list
...@@ -59,11 +59,11 @@ class APP_LIST_EXPORT SearchResultContainerView : public views::View, ...@@ -59,11 +59,11 @@ class APP_LIST_EXPORT SearchResultContainerView : public views::View,
// Updates the distance_from_origin() properties of the results in this // Updates the distance_from_origin() properties of the results in this
// container. |y_index| is the absolute y-index of the first result of this // container. |y_index| is the absolute y-index of the first result of this
// container (counting from the top of the app list). // container (counting from the top of the app list).
virtual void NotifyFirstResultYIndex(int y_index) = 0; virtual void NotifyFirstResultYIndex(int y_index);
// Gets the number of down keystrokes from the beginning to the end of this // Gets the number of down keystrokes from the beginning to the end of this
// container. // container.
virtual int GetYSize() = 0; virtual int GetYSize();
// Batching method that actually performs the update and updates layout. // Batching method that actually performs the update and updates layout.
void Update(); void Update();
...@@ -85,15 +85,14 @@ class APP_LIST_EXPORT SearchResultContainerView : public views::View, ...@@ -85,15 +85,14 @@ class APP_LIST_EXPORT SearchResultContainerView : public views::View,
// above. |directional_movement| is true if the navigation was caused by // above. |directional_movement| is true if the navigation was caused by
// directional controls (eg, arrow keys), as opposed to linear controls (eg, // directional controls (eg, arrow keys), as opposed to linear controls (eg,
// Tab). // Tab).
virtual void OnContainerSelected(bool from_bottom, virtual void OnContainerSelected(bool from_bottom, bool directional_movement);
bool directional_movement) = 0;
// Returns selected view in this container view. // Returns selected view in this container view.
virtual views::View* GetSelectedView() = 0; virtual views::View* GetSelectedView();
// Returns the first result in the container view. Returns NULL if it does not // Returns the first result in the container view. Returns NULL if it does not
// exist. // exist.
virtual SearchResultBaseView* GetFirstResultView() = 0; virtual SearchResultBaseView* GetFirstResultView();
private: private:
// Schedules an Update call using |update_factory_|. Do nothing if there is a // Schedules an Update call using |update_factory_|. Do nothing if there is a
...@@ -104,7 +103,7 @@ class APP_LIST_EXPORT SearchResultContainerView : public views::View, ...@@ -104,7 +103,7 @@ class APP_LIST_EXPORT SearchResultContainerView : public views::View,
virtual int DoUpdate() = 0; virtual int DoUpdate() = 0;
// Updates UI for a change in the selected index. // Updates UI for a change in the selected index.
virtual void UpdateSelectedIndex(int old_selected, int new_selected) = 0; virtual void UpdateSelectedIndex(int old_selected, int new_selected);
Delegate* delegate_; Delegate* delegate_;
......
// 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.
#include "ash/app_list/views/search_result_suggestion_chip_view.h"
#include <utility>
#include "ash/app_list/app_list_metrics.h"
#include "ash/app_list/app_list_view_delegate.h"
#include "ash/app_list/model/search/search_result.h"
#include "ash/public/cpp/app_list/app_list_constants.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
namespace app_list {
namespace {
// Records an app being launched.
void LogAppLaunch() {
UMA_HISTOGRAM_BOOLEAN(kAppListAppLaunchedFullscreen,
true /* suggested app */);
base::RecordAction(base::UserMetricsAction("AppList_OpenSuggestedApp"));
}
} // namespace
SearchResultSuggestionChipView::SearchResultSuggestionChipView(
AppListViewDelegate* view_delegate)
: view_delegate_(view_delegate), weak_ptr_factory_(this) {}
SearchResultSuggestionChipView::~SearchResultSuggestionChipView() {
DiscardItem();
}
void SearchResultSuggestionChipView::SetSearchResult(SearchResult* item) {
// Replace old item with new item.
DiscardItem();
if (!item)
return;
item_ = item;
item_->AddObserver(this);
app_list::SuggestionChipView::Params params;
params.text = item->title();
params.icon = item->icon();
suggestion_chip_view_ = new SuggestionChipView(params, /* listener */ this);
AddChildView(suggestion_chip_view_);
}
void SearchResultSuggestionChipView::OnResultDestroying() {
SetSearchResult(nullptr);
}
void SearchResultSuggestionChipView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
DCHECK(item_);
LogAppLaunch();
RecordSearchResultOpenSource(item_, view_delegate_->GetModel(),
view_delegate_->GetSearchModel());
view_delegate_->OpenSearchResult(item_->id(), event.flags());
}
void SearchResultSuggestionChipView::Layout() {
gfx::Rect rect(GetContentsBounds());
if (rect.IsEmpty() || !item_)
return;
suggestion_chip_view_->SetBoundsRect(rect);
}
const char* SearchResultSuggestionChipView::GetClassName() const {
return "SearchResultSuggestionChipView";
}
gfx::Size SearchResultSuggestionChipView::CalculatePreferredSize() const {
if (!suggestion_chip_view_)
return gfx::Size();
return suggestion_chip_view_->GetPreferredSize();
}
void SearchResultSuggestionChipView::DiscardItem() {
delete suggestion_chip_view_;
if (item_)
item_->RemoveObserver(this);
item_ = nullptr;
}
} // namespace app_list
// 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.
#ifndef ASH_APP_LIST_VIEWS_SEARCH_RESULT_SUGGESTION_CHIP_VIEW_H_
#define ASH_APP_LIST_VIEWS_SEARCH_RESULT_SUGGESTION_CHIP_VIEW_H_
#include <memory>
#include "ash/app_list/app_list_export.h"
#include "ash/app_list/views/search_result_base_view.h"
#include "ash/app_list/views/suggestion_chip_view.h"
#include "base/macros.h"
namespace app_list {
class AppListViewDelegate;
class SearchResult;
// A chip view that displays a search result.
class APP_LIST_EXPORT SearchResultSuggestionChipView
: public SearchResultBaseView {
public:
explicit SearchResultSuggestionChipView(AppListViewDelegate* view_delegate);
~SearchResultSuggestionChipView() override;
SearchResult* result() { return item_; }
void SetSearchResult(SearchResult* item);
// SearchResultObserver:
void OnResultDestroying() override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// views::View:
void Layout() override;
const char* GetClassName() const override;
gfx::Size CalculatePreferredSize() const override;
private:
// Remove the search result item.
void DiscardItem();
AppListViewDelegate* const view_delegate_; // Owned by AppListView.
// Owned by the model provided by the AppListViewDelegate.
SearchResult* item_ = nullptr;
// The view that actually shows the icon and title.
SuggestionChipView* suggestion_chip_view_ = nullptr;
base::WeakPtrFactory<SearchResultSuggestionChipView> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(SearchResultSuggestionChipView);
};
} // namespace app_list
#endif // ASH_APP_LIST_VIEWS_SEARCH_RESULT_SUGGESTION_CHIP_VIEW_H_
// 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.
#include "ash/app_list/views/suggestion_chip_container_view.h"
#include <memory>
#include "ash/app_list/views/app_list_main_view.h"
#include "ash/app_list/views/contents_view.h"
#include "ash/app_list/views/search_result_suggestion_chip_view.h"
#include "ash/public/cpp/app_list/app_list_config.h"
#include "ash/public/cpp/app_list/app_list_constants.h"
#include "ash/public/cpp/app_list/app_list_features.h"
#include "ui/views/layout/box_layout.h"
namespace app_list {
namespace {
// The spacing between chips.
constexpr int kChipSpacing = 8;
} // namespace
SuggestionChipContainerView::SuggestionChipContainerView(
ContentsView* contents_view)
: contents_view_(contents_view) {
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
DCHECK(contents_view);
view_delegate_ = contents_view_->GetAppListMainView()->view_delegate();
views::BoxLayout* layout_manager =
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
kChipSpacing));
layout_manager->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::MAIN_AXIS_ALIGNMENT_CENTER);
}
SuggestionChipContainerView::~SuggestionChipContainerView() = default;
int SuggestionChipContainerView::DoUpdate() {
if (IgnoreUpdateAndLayout())
return num_results();
// Clear all current suggestion chips.
for (size_t i = 0; i < suggestion_chip_views.size(); ++i)
delete suggestion_chip_views[i];
suggestion_chip_views.clear();
std::vector<SearchResult*> display_results =
SearchModel::FilterSearchResultsByDisplayType(
results(), ash::SearchResultDisplayType::kRecommendation,
kNumStartPageTiles);
// Create a suggestion chip for each search result, but wait until layout to
// add them as child views when we know this view's bounds.
for (auto* result : display_results) {
SearchResultSuggestionChipView* chip =
new SearchResultSuggestionChipView(view_delegate_);
chip->SetSearchResult(result);
suggestion_chip_views.emplace_back(chip);
}
return num_results();
}
const char* SuggestionChipContainerView::GetClassName() const {
return "SuggestionChipContainerView";
}
void SuggestionChipContainerView::Layout() {
if (IgnoreUpdateAndLayout())
return;
// Only show the chips that fit in this view's contents bounds.
RemoveAllChildViews(false /* delete_children */);
int total_width = 0;
const int max_width = GetContentsBounds().width();
for (auto* chip : suggestion_chip_views) {
const int chip_width = chip->GetPreferredSize().width();
if (chip_width + total_width > max_width)
break;
AddChildView(chip);
total_width += (total_width == 0 ? 0 : kChipSpacing) + chip_width;
}
views::View::Layout();
}
bool SuggestionChipContainerView::IgnoreUpdateAndLayout() const {
// Ignore update and layout when this view is not shown.
const ash::AppListState state = contents_view_->GetActiveState();
return state != ash::AppListState::kStateStart &&
state != ash::AppListState::kStateApps;
}
} // namespace app_list
// 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.
#ifndef ASH_APP_LIST_VIEWS_SUGGESTION_CHIP_CONTAINER_VIEW_H_
#define ASH_APP_LIST_VIEWS_SUGGESTION_CHIP_CONTAINER_VIEW_H_
#include <vector>
#include "ash/app_list/views/search_result_container_view.h"
#include "base/macros.h"
namespace app_list {
class AppListViewDelegate;
class ContentsView;
class SearchResultSuggestionChipView;
// A container that holds the suggestion chips.
class SuggestionChipContainerView : public SearchResultContainerView {
public:
explicit SuggestionChipContainerView(ContentsView* contents_view);
~SuggestionChipContainerView() override;
// SearchResultContainerView:
int DoUpdate() override;
const char* GetClassName() const override;
// views::View:
void Layout() override;
private:
// Returns true if update and layout should be ignored.
bool IgnoreUpdateAndLayout() const;
ContentsView* contents_view_ = nullptr; // Not owned
AppListViewDelegate* view_delegate_ = nullptr;
std::vector<SearchResultSuggestionChipView*> suggestion_chip_views; // Owned
DISALLOW_COPY_AND_ASSIGN(SuggestionChipContainerView);
};
} // namespace app_list
#endif // ASH_APP_LIST_VIEWS_SUGGESTION_CHIP_CONTAINER_VIEW_H_
...@@ -6,8 +6,14 @@ ...@@ -6,8 +6,14 @@
#include <memory> #include <memory>
#include "ash/public/cpp/app_list/app_list_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h" #include "ui/gfx/color_palette.h"
#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/ink_drop_mask.h"
#include "ui/views/animation/ink_drop_painted_layer_delegates.h"
#include "ui/views/background.h" #include "ui/views/background.h"
#include "ui/views/controls/image_view.h" #include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
...@@ -17,16 +23,25 @@ namespace app_list { ...@@ -17,16 +23,25 @@ namespace app_list {
namespace { namespace {
// Colors. // Assistant specific style:
constexpr SkColor kBackgroundColor = SK_ColorWHITE; constexpr SkColor kAssistantBackgroundColor = SK_ColorWHITE;
constexpr SkColor kStrokeColor = SkColorSetA(gfx::kGoogleGrey900, 0x24); constexpr SkColor kAssistantStrokeColor =
constexpr SkColor kTextColor = gfx::kGoogleGrey900; SkColorSetA(gfx::kGoogleGrey900, 0x24);
constexpr SkColor kAssistantTextColor = gfx::kGoogleGrey900;
// Dimensions. constexpr int kAssistantStrokeWidthDip = 1;
// App list specific style:
constexpr SkColor kAppListBackgroundColor =
SkColorSetA(gfx::kGoogleGrey900, 0x33);
constexpr SkColor kAppListTextColor = gfx::kGoogleGrey100;
constexpr SkColor kAppListRippleColor = SkColorSetA(gfx::kGoogleGrey100, 0x0F);
constexpr SkColor kAppListFocusColor = SkColorSetA(gfx::kGoogleGrey100, 0x14);
// Shared style:
constexpr int kIconMarginDip = 8; constexpr int kIconMarginDip = 8;
constexpr int kPaddingDip = 16; constexpr int kPaddingDip = 16;
constexpr int kPreferredHeightDip = 32; constexpr int kPreferredHeightDip = 32;
constexpr int kStrokeWidthDip = 1; constexpr int kIconSizeDip = 16;
} // namespace } // namespace
...@@ -39,10 +54,15 @@ SuggestionChipView::Params::~Params() = default; ...@@ -39,10 +54,15 @@ SuggestionChipView::Params::~Params() = default;
// SuggestionChipView ---------------------------------------------------------- // SuggestionChipView ----------------------------------------------------------
SuggestionChipView::SuggestionChipView(const Params& params, SuggestionChipView::SuggestionChipView(const Params& params,
SuggestionChipListener* listener) views::ButtonListener* listener)
: icon_view_(new views::ImageView()), : Button(listener),
icon_view_(new views::ImageView()),
text_view_(new views::Label()), text_view_(new views::Label()),
listener_(listener) { assistant_style_(params.assistant_style) {
if (!assistant_style_) {
SetFocusBehavior(FocusBehavior::ALWAYS);
SetInkDropMode(InkDropHostView::InkDropMode::ON);
}
InitLayout(params); InitLayout(params);
} }
...@@ -92,8 +112,11 @@ void SuggestionChipView::InitLayout(const Params& params) { ...@@ -92,8 +112,11 @@ void SuggestionChipView::InitLayout(const Params& params) {
// Text. // Text.
text_view_->SetAutoColorReadabilityEnabled(false); text_view_->SetAutoColorReadabilityEnabled(false);
text_view_->SetEnabledColor(kTextColor); text_view_->SetEnabledColor(assistant_style_ ? kAssistantTextColor
text_view_->SetFontList(text_view_->font_list().DeriveWithSizeDelta(2)); : kAppListTextColor);
text_view_->SetFontList(assistant_style_
? text_view_->font_list().DeriveWithSizeDelta(2)
: AppListConfig::instance().app_title_font());
text_view_->SetText(params.text); text_view_->SetText(params.text);
AddChildView(text_view_); AddChildView(text_view_);
} }
...@@ -105,31 +128,66 @@ void SuggestionChipView::OnPaintBackground(gfx::Canvas* canvas) { ...@@ -105,31 +128,66 @@ void SuggestionChipView::OnPaintBackground(gfx::Canvas* canvas) {
gfx::Rect bounds = GetContentsBounds(); gfx::Rect bounds = GetContentsBounds();
// Background. // Background.
flags.setColor(kBackgroundColor); flags.setColor(assistant_style_ ? kAssistantBackgroundColor
: kAppListBackgroundColor);
canvas->DrawRoundRect(bounds, height() / 2, flags); canvas->DrawRoundRect(bounds, height() / 2, flags);
// Stroke should be drawn within our contents bounds. if (assistant_style_) {
bounds.Inset(gfx::Insets(kStrokeWidthDip)); // Stroke should be drawn within our contents bounds.
bounds.Inset(gfx::Insets(kAssistantStrokeWidthDip));
// Stroke. // Stroke.
flags.setColor(kStrokeColor); flags.setColor(kAssistantStrokeColor);
flags.setStrokeWidth(kStrokeWidthDip); flags.setStrokeWidth(kAssistantStrokeWidthDip);
flags.setStyle(cc::PaintFlags::Style::kStroke_Style); flags.setStyle(cc::PaintFlags::Style::kStroke_Style);
canvas->DrawRoundRect(bounds, height() / 2, flags); canvas->DrawRoundRect(bounds, height() / 2, flags);
} return;
}
void SuggestionChipView::OnGestureEvent(ui::GestureEvent* event) { if (HasFocus()) {
if (event->type() == ui::ET_GESTURE_TAP) { flags.setColor(kAppListFocusColor);
if (listener_) canvas->DrawRoundRect(bounds, height() / 2, flags);
listener_->OnSuggestionChipPressed(this);
event->SetHandled();
} }
} }
bool SuggestionChipView::OnMousePressed(const ui::MouseEvent& event) { void SuggestionChipView::OnFocus() {
if (listener_) SchedulePaint();
listener_->OnSuggestionChipPressed(this); NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
return true; }
void SuggestionChipView::OnBlur() {
SchedulePaint();
}
void SuggestionChipView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kButton;
node_data->SetName(GetText());
}
std::unique_ptr<views::InkDrop> SuggestionChipView::CreateInkDrop() {
std::unique_ptr<views::InkDropImpl> ink_drop =
Button::CreateDefaultInkDropImpl();
ink_drop->SetShowHighlightOnHover(false);
ink_drop->SetShowHighlightOnFocus(false);
ink_drop->SetAutoHighlightMode(views::InkDropImpl::AutoHighlightMode::NONE);
return std::move(ink_drop);
}
std::unique_ptr<views::InkDropMask> SuggestionChipView::CreateInkDropMask()
const {
return std::make_unique<views::RoundRectInkDropMask>(size(), gfx::InsetsF(),
height() / 2);
}
std::unique_ptr<views::InkDropRipple> SuggestionChipView::CreateInkDropRipple()
const {
const gfx::Point center = GetLocalBounds().CenterPoint();
const int ripple_radius = width() / 2;
gfx::Rect bounds(center.x() - ripple_radius, center.y() - ripple_radius,
2 * ripple_radius, 2 * ripple_radius);
return std::make_unique<views::FloodFillInkDropRipple>(
size(), GetLocalBounds().InsetsFrom(bounds),
GetInkDropCenterBasedOnLastEvent(), kAppListRippleColor, 1.0f);
} }
void SuggestionChipView::SetIcon(const gfx::ImageSkia& icon) { void SuggestionChipView::SetIcon(const gfx::ImageSkia& icon) {
......
...@@ -8,11 +8,14 @@ ...@@ -8,11 +8,14 @@
#include "ash/app_list/app_list_export.h" #include "ash/app_list/app_list_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
#include "ui/views/view.h" #include "ui/views/controls/button/button.h"
namespace views { namespace views {
class BoxLayout; class BoxLayout;
class ImageView; class ImageView;
class InkDrop;
class InkDropMask;
class InkDropRipple;
class Label; class Label;
} // namespace views } // namespace views
...@@ -20,21 +23,9 @@ namespace app_list { ...@@ -20,21 +23,9 @@ namespace app_list {
class SuggestionChipView; class SuggestionChipView;
// Listener which receives notification of suggestion chip events.
class APP_LIST_EXPORT SuggestionChipListener {
public:
// Invoked when the specified |sender| is pressed.
virtual void OnSuggestionChipPressed(SuggestionChipView* sender) = 0;
protected:
virtual ~SuggestionChipListener() = default;
};
// View representing a suggestion chip. // View representing a suggestion chip.
class APP_LIST_EXPORT SuggestionChipView : public views::View { class APP_LIST_EXPORT SuggestionChipView : public views::Button {
public: public:
static constexpr int kIconSizeDip = 16;
// Initialization parameters. // Initialization parameters.
struct Params { struct Params {
Params(); Params();
...@@ -44,19 +35,26 @@ class APP_LIST_EXPORT SuggestionChipView : public views::View { ...@@ -44,19 +35,26 @@ class APP_LIST_EXPORT SuggestionChipView : public views::View {
base::string16 text; base::string16 text;
// Optional icon. // Optional icon.
base::Optional<gfx::ImageSkia> icon; base::Optional<gfx::ImageSkia> icon;
// True if the chip should use assistant style.
bool assistant_style = false;
}; };
SuggestionChipView(const Params& params, SuggestionChipView(const Params& params, views::ButtonListener* listener);
SuggestionChipListener* listener = nullptr);
~SuggestionChipView() override; ~SuggestionChipView() override;
// views::View: // views::View:
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
void ChildVisibilityChanged(views::View* child) override; void ChildVisibilityChanged(views::View* child) override;
int GetHeightForWidth(int width) const override; int GetHeightForWidth(int width) const override;
void OnGestureEvent(ui::GestureEvent* event) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
void OnPaintBackground(gfx::Canvas* canvas) override; void OnPaintBackground(gfx::Canvas* canvas) override;
void OnFocus() override;
void OnBlur() override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
// views::InkDropHost:
std::unique_ptr<views::InkDrop> CreateInkDrop() override;
std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
void SetIcon(const gfx::ImageSkia& icon); void SetIcon(const gfx::ImageSkia& icon);
...@@ -67,10 +65,12 @@ class APP_LIST_EXPORT SuggestionChipView : public views::View { ...@@ -67,10 +65,12 @@ class APP_LIST_EXPORT SuggestionChipView : public views::View {
views::ImageView* icon_view_; // Owned by view hierarchy. views::ImageView* icon_view_; // Owned by view hierarchy.
views::Label* text_view_; // Owned by view hierarchy. views::Label* text_view_; // Owned by view hierarchy.
SuggestionChipListener* listener_;
views::BoxLayout* layout_manager_; // Owned by view hierarchy. views::BoxLayout* layout_manager_; // Owned by view hierarchy.
// True if this chip should use assistant style.
bool assistant_style_;
DISALLOW_COPY_AND_ASSIGN(SuggestionChipView); DISALLOW_COPY_AND_ASSIGN(SuggestionChipView);
}; };
......
...@@ -74,34 +74,12 @@ int SuggestionsContainerView::DoUpdate() { ...@@ -74,34 +74,12 @@ int SuggestionsContainerView::DoUpdate() {
return display_results.size(); return display_results.size();
} }
void SuggestionsContainerView::UpdateSelectedIndex(int old_selected,
int new_selected) {}
void SuggestionsContainerView::OnContainerSelected(
bool /*from_bottom*/,
bool /*directional_movement*/) {
NOTREACHED();
}
void SuggestionsContainerView::NotifyFirstResultYIndex(int /*y_index*/) {
NOTREACHED();
}
int SuggestionsContainerView::GetYSize() {
NOTREACHED();
return 0;
}
views::View* SuggestionsContainerView::GetSelectedView() { views::View* SuggestionsContainerView::GetSelectedView() {
return IsValidSelectionIndex(selected_index()) return IsValidSelectionIndex(selected_index())
? search_result_tile_views_[selected_index()] ? search_result_tile_views_[selected_index()]
: nullptr; : nullptr;
} }
SearchResultBaseView* SuggestionsContainerView::GetFirstResultView() {
return nullptr;
}
const char* SuggestionsContainerView::GetClassName() const { const char* SuggestionsContainerView::GetClassName() const {
return "SuggestionsContainerView"; return "SuggestionsContainerView";
} }
......
...@@ -31,13 +31,7 @@ class SuggestionsContainerView : public SearchResultContainerView { ...@@ -31,13 +31,7 @@ class SuggestionsContainerView : public SearchResultContainerView {
// Overridden from SearchResultContainerView: // Overridden from SearchResultContainerView:
int DoUpdate() override; int DoUpdate() override;
void UpdateSelectedIndex(int old_selected, int new_selected) override;
void OnContainerSelected(bool from_bottom,
bool directional_movement) override;
void NotifyFirstResultYIndex(int y_index) override;
int GetYSize() override;
views::View* GetSelectedView() override; views::View* GetSelectedView() override;
SearchResultBaseView* GetFirstResultView() override;
const char* GetClassName() const override; const char* GetClassName() const override;
private: private:
......
...@@ -90,6 +90,7 @@ void SuggestionContainerView::OnSuggestionsAdded( ...@@ -90,6 +90,7 @@ void SuggestionContainerView::OnSuggestionsAdded(
const int id = suggestion.first; const int id = suggestion.first;
app_list::SuggestionChipView::Params params; app_list::SuggestionChipView::Params params;
params.assistant_style = true;
params.text = base::UTF8ToUTF16(suggestion.second->text); params.text = base::UTF8ToUTF16(suggestion.second->text);
if (!suggestion.second->icon_url.is_empty()) { if (!suggestion.second->icon_url.is_empty()) {
...@@ -140,10 +141,10 @@ void SuggestionContainerView::OnSuggestionChipIconDownloaded( ...@@ -140,10 +141,10 @@ void SuggestionContainerView::OnSuggestionChipIconDownloaded(
suggestion_chip_views_[id]->SetIcon(icon); suggestion_chip_views_[id]->SetIcon(icon);
} }
void SuggestionContainerView::OnSuggestionChipPressed( void SuggestionContainerView::ButtonPressed(views::Button* sender,
app_list::SuggestionChipView* suggestion_chip_view) { const ui::Event& event) {
assistant_controller_->interaction_controller()->OnSuggestionChipPressed( assistant_controller_->interaction_controller()->OnSuggestionChipPressed(
suggestion_chip_view->id()); static_cast<app_list::SuggestionChipView*>(sender)->id());
} }
void SuggestionContainerView::UpdateContentsBounds() { void SuggestionContainerView::UpdateContentsBounds() {
......
...@@ -21,7 +21,7 @@ class AssistantController; ...@@ -21,7 +21,7 @@ class AssistantController;
// suggestion events. // suggestion events.
class SuggestionContainerView : public views::ScrollView, class SuggestionContainerView : public views::ScrollView,
public AssistantInteractionModelObserver, public AssistantInteractionModelObserver,
public app_list::SuggestionChipListener { public views::ButtonListener {
public: public:
using AssistantSuggestion = chromeos::assistant::mojom::AssistantSuggestion; using AssistantSuggestion = chromeos::assistant::mojom::AssistantSuggestion;
...@@ -37,9 +37,8 @@ class SuggestionContainerView : public views::ScrollView, ...@@ -37,9 +37,8 @@ class SuggestionContainerView : public views::ScrollView,
const std::map<int, AssistantSuggestion*>& suggestions) override; const std::map<int, AssistantSuggestion*>& suggestions) override;
void OnSuggestionsCleared() override; void OnSuggestionsCleared() override;
// app_list::SuggestionChipListener: // views::ButtonListener:
void OnSuggestionChipPressed( void ButtonPressed(views::Button* sender, const ui::Event& event) override;
app_list::SuggestionChipView* suggestion_chip_view) override;
private: private:
void InitLayout(); void InitLayout();
......
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