From cc60e6cae4759311c0c4c04b21c2032f81abdca6 Mon Sep 17 00:00:00 2001
From: Ana Salazar <anasalazar@chromium.org>
Date: Mon, 2 Aug 2021 19:18:45 +0000
Subject: [PATCH] [launcher]: Layout Continue Task elements
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Create a basic layout for the elements inside the ContinueTaskView

This CL adds a title and a subtitle for the task as well as a rounded
image icon.

The sizes are calculated based on the launcher spec and may be modified
later. We also need to add some spacing and paddings to the views that
comprise the ContinueSection as well.

For the styling of the subtitle label, we added a new Style type in
bubble utils kSubtitle which is used in the Continue Section header as
well.
As for the subtitle, we use for now the details field of the
SearchResult which contains the File Type. We expect to fetch the last
used time in the future.

Bug: 1216084
Change-Id: I1e75e56bb51ecfee7874c6af5d9174e8db7b6fc5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3059799
Commit-Queue: Ana Salazar <anasalazar@chromium.org>
Reviewed-by: James Cook <jamescook@chromium.org>
Reviewed-by: Toni Baržić <tbarzic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#907651}
---
 .../views/app_list_bubble_apps_page.cc        |  9 ++-
 ash/app_list/views/continue_section_view.cc   | 30 +++++-----
 ash/app_list/views/continue_section_view.h    |  3 +-
 ash/app_list/views/continue_task_view.cc      | 56 ++++++++++++++++---
 ash/app_list/views/continue_task_view.h       | 11 ++--
 ash/bubble/bubble_utils.cc                    | 16 +++++-
 ash/bubble/bubble_utils.h                     |  1 +
 7 files changed, 93 insertions(+), 33 deletions(-)

diff --git a/ash/app_list/views/app_list_bubble_apps_page.cc b/ash/app_list/views/app_list_bubble_apps_page.cc
index 6cedd7ddf6053..c4c51187ca44d 100644
--- a/ash/app_list/views/app_list_bubble_apps_page.cc
+++ b/ash/app_list/views/app_list_bubble_apps_page.cc
@@ -30,6 +30,10 @@ using views::BoxLayout;
 
 namespace ash {
 
+namespace {
+constexpr int kContinueColumnCount = 2;
+}  // namespace
+
 AppListBubbleAppsPage::AppListBubbleAppsPage(
     AppListViewDelegate* view_delegate,
     ApplicationDragAndDropHost* drag_and_drop_host) {
@@ -56,8 +60,9 @@ AppListBubbleAppsPage::AppListBubbleAppsPage(
   layout->set_cross_axis_alignment(BoxLayout::CrossAxisAlignment::kStretch);
 
   // Continue section row.
-  continue_section_ = scroll_contents->AddChildView(
-      std::make_unique<ContinueSectionView>(view_delegate));
+  continue_section_ =
+      scroll_contents->AddChildView(std::make_unique<ContinueSectionView>(
+          view_delegate, kContinueColumnCount));
 
   // Recent apps row.
   recent_apps_ = scroll_contents->AddChildView(
diff --git a/ash/app_list/views/continue_section_view.cc b/ash/app_list/views/continue_section_view.cc
index af83b1a866391..4ff34b76347e5 100644
--- a/ash/app_list/views/continue_section_view.cc
+++ b/ash/app_list/views/continue_section_view.cc
@@ -26,16 +26,17 @@
 namespace ash {
 namespace {
 
-// Horizontal space between suggestions in dips.
-constexpr int kHorizontalSpacing = 8;
+// Vertical space between header and content in dips.
+constexpr int kVerticalSpacing = 8;
 
-constexpr int kContinueColumnCount = 2;
-constexpr int kContinueColumnSpacing = 16;
-constexpr int kContinueRowSpacing = 10;
+// Continue files section constants.
+constexpr int kContinueColumnSpacing = 8;
+constexpr int kContinueRowSpacing = 8;
+constexpr int kMinFilesForContinueSection = 3;
 
-std::unique_ptr<views::Label> CreateLabel(const std::u16string& text) {
+std::unique_ptr<views::Label> CreateContinueLabel(const std::u16string& text) {
   auto label = std::make_unique<views::Label>(text);
-  bubble_utils::ApplyStyle(label.get(), bubble_utils::LabelStyle::kBody);
+  bubble_utils::ApplyStyle(label.get(), bubble_utils::LabelStyle::kSubtitle);
   return label;
 }
 
@@ -75,23 +76,24 @@ std::vector<SearchResult*> GetTasksResultsFromSuggestionChips(
 
 }  // namespace
 
-ContinueSectionView::ContinueSectionView(AppListViewDelegate* view_delegate)
-    : view_delegate_(view_delegate) {
+ContinueSectionView::ContinueSectionView(AppListViewDelegate* view_delegate,
+                                         int columns)
+    : view_delegate_(view_delegate), columns_(columns) {
   DCHECK(view_delegate_);
 
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical, gfx::Insets(),
-      kHorizontalSpacing));
-  layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter);
+      kVerticalSpacing));
+  layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
 
   // TODO(https://crbug.com/1204551): Localized strings.
   // TODO(https://crbug.com/1204551): Styling.
-  auto* continue_label = AddChildView(CreateLabel(u"Label"));
+  auto* continue_label = AddChildView(CreateContinueLabel(u"Continue"));
   continue_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
 
   suggestions_container_ = AddChildView(std::make_unique<views::View>());
   suggestions_container_->SetLayoutManager(std::make_unique<SimpleGridLayout>(
-      kContinueColumnCount, kContinueColumnSpacing, kContinueRowSpacing));
+      columns_, kContinueColumnSpacing, kContinueRowSpacing));
 
   std::vector<SearchResult*> tasks =
       GetTasksResultsFromSuggestionChips(view_delegate_->GetSearchModel());
@@ -100,7 +102,7 @@ ContinueSectionView::ContinueSectionView(AppListViewDelegate* view_delegate)
     suggestions_container_->AddChildView(
         std::make_unique<ContinueTaskView>(task));
   }
-  SetVisible(!tasks.empty());
+  SetVisible(GetTasksSuggestionsCount() > kMinFilesForContinueSection);
 }
 
 ContinueSectionView::~ContinueSectionView() = default;
diff --git a/ash/app_list/views/continue_section_view.h b/ash/app_list/views/continue_section_view.h
index 11b89d2739b8e..160697f3e9d3b 100644
--- a/ash/app_list/views/continue_section_view.h
+++ b/ash/app_list/views/continue_section_view.h
@@ -19,7 +19,7 @@ class ASH_EXPORT ContinueSectionView : public views::View {
  public:
   METADATA_HEADER(ContinueSectionView);
 
-  explicit ContinueSectionView(AppListViewDelegate* view_delegate);
+  ContinueSectionView(AppListViewDelegate* view_delegate, int columns);
   ContinueSectionView(const ContinueSectionView&) = delete;
   ContinueSectionView& operator=(const ContinueSectionView&) = delete;
   ~ContinueSectionView() override;
@@ -30,6 +30,7 @@ class ASH_EXPORT ContinueSectionView : public views::View {
  private:
   AppListViewDelegate* const view_delegate_;
 
+  const int columns_;
   views::View* suggestions_container_ = nullptr;
 };
 
diff --git a/ash/app_list/views/continue_task_view.cc b/ash/app_list/views/continue_task_view.cc
index dc1be4ded9fc8..dcc5c6ac5b2ab 100644
--- a/ash/app_list/views/continue_task_view.cc
+++ b/ash/app_list/views/continue_task_view.cc
@@ -9,34 +9,72 @@
 #include <string>
 #include <utility>
 
+#include "ash/app_list/app_list_util.h"
 #include "ash/app_list/model/search/search_result.h"
 #include "ash/bubble/bubble_utils.h"
+#include "ash/style/ash_color_provider.h"
 #include "base/strings/string_util.h"
 #include "extensions/common/constants.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
-#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/box_layout.h"
 
 namespace ash {
+namespace {
+constexpr int kIconSize = 36;
+constexpr int kPreferredWidth = 242;
+constexpr int kPreferredHeight = 52;
+}  // namespace
 
 ContinueTaskView::ContinueTaskView(SearchResult* task_result)
     : result_(task_result) {
-  SetLayoutManager(std::make_unique<views::FillLayout>());
-  title_ = AddChildView(std::make_unique<views::Label>());
-  SetText(result()->title());
+  SetFocusBehavior(FocusBehavior::ALWAYS);
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kHorizontal));
+  GetViewAccessibility().OverrideName(result()->title() + u" " +
+                                      result()->details());
+  GetViewAccessibility().OverrideRole(ax::mojom::Role::kListItem);
+
+  icon_ = AddChildView(std::make_unique<views::ImageView>());
+  icon_->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
+  SetIcon(result()->chip_icon());
+
+  auto* label_container = AddChildView(std::make_unique<views::View>());
+  label_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
+
+  title_ = label_container->AddChildView(
+      std::make_unique<views::Label>(result()->title()));
   title_->SetAccessibleName(result()->accessible_name());
+  title_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
+  subtitle_ = label_container->AddChildView(
+      std::make_unique<views::Label>(result()->details()));
+  subtitle_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
+
+  SetPreferredSize(gfx::Size(kPreferredWidth, kPreferredHeight));
 }
 
 ContinueTaskView::~ContinueTaskView() = default;
 
-void ContinueTaskView::SetText(const std::u16string& text) {
-  title_->SetText(text);
-  PreferredSizeChanged();
-}
-
 void ContinueTaskView::OnThemeChanged() {
   views::View::OnThemeChanged();
   bubble_utils::ApplyStyle(title_, bubble_utils::LabelStyle::kBody);
+  bubble_utils::ApplyStyle(subtitle_, bubble_utils::LabelStyle::kSubtitle);
+}
+
+void ContinueTaskView::SetIcon(const gfx::ImageSkia& icon) {
+  gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
+      icon, skia::ImageOperations::RESIZE_BEST, GetIconSize()));
+  icon_->SetImage(resized);
+  icon_->SetImageSize(GetIconSize());
+}
+
+gfx::Size ContinueTaskView::GetIconSize() const {
+  return gfx::Size(kIconSize, kIconSize);
 }
 
 BEGIN_METADATA(ContinueTaskView, views::View)
diff --git a/ash/app_list/views/continue_task_view.h b/ash/app_list/views/continue_task_view.h
index 555d231d713dc..8d122e185a80e 100644
--- a/ash/app_list/views/continue_task_view.h
+++ b/ash/app_list/views/continue_task_view.h
@@ -5,13 +5,11 @@
 #ifndef ASH_APP_LIST_VIEWS_CONTINUE_TASK_VIEW_H_
 #define ASH_APP_LIST_VIEWS_CONTINUE_TASK_VIEW_H_
 
-#include <memory>
-#include <string>
-
 #include "ash/ash_export.h"
 #include "ui/views/view.h"
 
 namespace views {
+class ImageView;
 class Label;
 }
 
@@ -34,10 +32,13 @@ class ASH_EXPORT ContinueTaskView : public views::View {
   SearchResult* result() { return result_; }
 
  private:
-  void SetText(const std::u16string& task_title);
+  void SetIcon(const gfx::ImageSkia& icon);
+  gfx::Size GetIconSize() const;
 
   SearchResult* result_;
-  views::Label* title_;
+  views::Label* title_ = nullptr;
+  views::Label* subtitle_ = nullptr;
+  views::ImageView* icon_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/ash/bubble/bubble_utils.cc b/ash/bubble/bubble_utils.cc
index 99a64c5c6c889..3d33e7fb77257 100644
--- a/ash/bubble/bubble_utils.cc
+++ b/ash/bubble/bubble_utils.cc
@@ -96,31 +96,43 @@ bool ShouldCloseBubbleForEvent(const ui::LocatedEvent& event) {
 
 void ApplyStyle(views::Label* label, LabelStyle style) {
   label->SetAutoColorReadabilityEnabled(false);
-  label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kTextColorPrimary));
+  AshColorProvider::ContentLayerType text_color;
 
   switch (style) {
     case LabelStyle::kBadge:
+      text_color = AshColorProvider::ContentLayerType::kTextColorPrimary;
       label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 14,
                                        gfx::Font::Weight::MEDIUM));
       break;
     case LabelStyle::kBody:
+      text_color = AshColorProvider::ContentLayerType::kTextColorPrimary;
       label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 14,
                                        gfx::Font::Weight::NORMAL));
       break;
     case LabelStyle::kChipBody:
+      text_color = AshColorProvider::ContentLayerType::kTextColorPrimary;
       label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 10,
                                        gfx::Font::Weight::MEDIUM));
       break;
     case LabelStyle::kChipTitle:
+      text_color = AshColorProvider::ContentLayerType::kTextColorPrimary;
       label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 13,
                                        gfx::Font::Weight::NORMAL));
       break;
     case LabelStyle::kHeader:
+      text_color = AshColorProvider::ContentLayerType::kTextColorPrimary;
       label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 16,
                                        gfx::Font::Weight::MEDIUM));
       break;
+    case LabelStyle::kSubtitle:
+      text_color = AshColorProvider::ContentLayerType::kTextColorSecondary;
+      label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 12,
+                                       gfx::Font::Weight::NORMAL));
+      break;
   }
+
+  label->SetEnabledColor(
+      AshColorProvider::Get()->GetContentLayerColor(text_color));
 }
 
 std::unique_ptr<views::Label> CreateLabel(LabelStyle style,
diff --git a/ash/bubble/bubble_utils.h b/ash/bubble/bubble_utils.h
index 93ec6f64e4fa7..e0ea3434c0006 100644
--- a/ash/bubble/bubble_utils.h
+++ b/ash/bubble/bubble_utils.h
@@ -34,6 +34,7 @@ enum class LabelStyle {
   kChipBody,
   kChipTitle,
   kHeader,
+  kSubtitle,
 };
 
 // Applies the specified `style` to the given `label`.