phone_hub_recent_apps_view.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/system/phonehub/phone_hub_recent_apps_view.h"
  5. #include <memory>
  6. #include <numeric>
  7. #include <vector>
  8. #include "ash/components/phonehub/notification.h"
  9. #include "ash/strings/grit/ash_strings.h"
  10. #include "ash/style/ash_color_provider.h"
  11. #include "ash/system/phonehub/phone_hub_recent_app_button.h"
  12. #include "ash/system/phonehub/phone_hub_view_ids.h"
  13. #include "ash/system/phonehub/ui_constants.h"
  14. #include "ash/system/tray/tray_constants.h"
  15. #include "base/cxx17_backports.h"
  16. #include "ui/base/l10n/l10n_util.h"
  17. #include "ui/gfx/geometry/insets.h"
  18. #include "ui/views/controls/label.h"
  19. #include "ui/views/layout/box_layout.h"
  20. namespace ash {
  21. namespace {
  22. using RecentAppsUiState =
  23. ::ash::phonehub::RecentAppsInteractionHandler::RecentAppsUiState;
  24. // Appearance constants in DIPs.
  25. constexpr gfx::Insets kRecentAppButtonFocusPadding(4);
  26. constexpr auto kContentTextLabelInsetsDip = gfx::Insets::TLBR(0, 4, 0, 4);
  27. constexpr int kHeaderLabelLineHeight = 30;
  28. constexpr int kRecentAppButtonDefaultSpacing = 42;
  29. constexpr int kRecentAppButtonMinSpacing = 4;
  30. constexpr int kRecentAppButtonSize = 32;
  31. constexpr int kRecentAppButtonsViewTopPadding = 12;
  32. constexpr int kContentLabelLineHeightDip = 20;
  33. // Typography.
  34. constexpr int kHeaderTextFontSizeDip = 15;
  35. class HeaderView : public views::Label {
  36. public:
  37. HeaderView() {
  38. SetText(l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_RECENT_APPS_TITLE));
  39. SetLineHeight(kHeaderLabelLineHeight);
  40. SetFontList(font_list()
  41. .DeriveWithSizeDelta(kHeaderTextFontSizeDip -
  42. font_list().GetFontSize())
  43. .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
  44. SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
  45. SetVerticalAlignment(gfx::VerticalAlignment::ALIGN_MIDDLE);
  46. SetAutoColorReadabilityEnabled(false);
  47. SetSubpixelRenderingEnabled(false);
  48. SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
  49. AshColorProvider::ContentLayerType::kTextColorPrimary));
  50. }
  51. ~HeaderView() override = default;
  52. HeaderView(HeaderView&) = delete;
  53. HeaderView operator=(HeaderView&) = delete;
  54. // views::View:
  55. const char* GetClassName() const override { return "HeaderView"; }
  56. };
  57. } // namespace
  58. class PhoneHubRecentAppsView::PlaceholderView : public views::Label {
  59. public:
  60. PlaceholderView() {
  61. SetText(
  62. l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_RECENT_APPS_PLACEHOLDER));
  63. SetLineHeight(kContentLabelLineHeightDip);
  64. SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
  65. SetAutoColorReadabilityEnabled(false);
  66. SetSubpixelRenderingEnabled(false);
  67. SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
  68. AshColorProvider::ContentLayerType::kTextColorPrimary));
  69. SetMultiLine(true);
  70. SetBorder(views::CreateEmptyBorder(kContentTextLabelInsetsDip));
  71. }
  72. ~PlaceholderView() override = default;
  73. PlaceholderView(PlaceholderView&) = delete;
  74. PlaceholderView operator=(PlaceholderView&) = delete;
  75. // views::View:
  76. const char* GetClassName() const override { return "ContentView"; }
  77. };
  78. PhoneHubRecentAppsView::PhoneHubRecentAppsView(
  79. phonehub::RecentAppsInteractionHandler* recent_apps_interaction_handler)
  80. : recent_apps_interaction_handler_(recent_apps_interaction_handler) {
  81. SetID(PhoneHubViewID::kPhoneHubRecentAppsView);
  82. auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
  83. views::BoxLayout::Orientation::kVertical));
  84. layout->set_cross_axis_alignment(
  85. views::BoxLayout::CrossAxisAlignment::kStart);
  86. AddChildView(std::make_unique<HeaderView>());
  87. recent_app_buttons_view_ =
  88. AddChildView(std::make_unique<RecentAppButtonsView>());
  89. placeholder_view_ = AddChildView(std::make_unique<PlaceholderView>());
  90. Update();
  91. recent_apps_interaction_handler_->AddObserver(this);
  92. }
  93. PhoneHubRecentAppsView::~PhoneHubRecentAppsView() {
  94. recent_apps_interaction_handler_->RemoveObserver(this);
  95. }
  96. const char* PhoneHubRecentAppsView::GetClassName() const {
  97. return "PhoneHubRecentAppsView";
  98. }
  99. PhoneHubRecentAppsView::RecentAppButtonsView::RecentAppButtonsView() = default;
  100. PhoneHubRecentAppsView::RecentAppButtonsView::~RecentAppButtonsView() = default;
  101. views::View* PhoneHubRecentAppsView::RecentAppButtonsView::AddRecentAppButton(
  102. std::unique_ptr<views::View> recent_app_button) {
  103. return AddChildView(std::move(recent_app_button));
  104. }
  105. // phonehub::RecentAppsInteractionHandler::Observer:
  106. void PhoneHubRecentAppsView::OnRecentAppsUiStateUpdated() {
  107. Update();
  108. }
  109. // views::View:
  110. gfx::Size PhoneHubRecentAppsView::RecentAppButtonsView::CalculatePreferredSize()
  111. const {
  112. int width = kTrayMenuWidth - kBubbleHorizontalSidePaddingDip * 2;
  113. int height = kRecentAppButtonSize + kRecentAppButtonFocusPadding.height() +
  114. kRecentAppButtonsViewTopPadding;
  115. return gfx::Size(width, height);
  116. }
  117. void PhoneHubRecentAppsView::RecentAppButtonsView::Layout() {
  118. const gfx::Rect child_area = GetContentsBounds();
  119. views::View::Views visible_children;
  120. std::copy_if(children().cbegin(), children().cend(),
  121. std::back_inserter(visible_children), [](const auto* v) {
  122. return v->GetVisible() && (v->GetPreferredSize().width() > 0);
  123. });
  124. if (visible_children.empty())
  125. return;
  126. const int visible_child_width =
  127. std::accumulate(visible_children.cbegin(), visible_children.cend(), 0,
  128. [](int width, const auto* v) {
  129. return width + v->GetPreferredSize().width();
  130. });
  131. int spacing = 0;
  132. if (visible_children.size() > 1) {
  133. spacing = (child_area.width() - visible_child_width) /
  134. (static_cast<int>(visible_children.size()) - 1);
  135. spacing = base::clamp(spacing, kRecentAppButtonMinSpacing,
  136. kRecentAppButtonDefaultSpacing);
  137. }
  138. int child_x = child_area.x();
  139. int child_y = child_area.y() + kRecentAppButtonsViewTopPadding +
  140. kRecentAppButtonFocusPadding.bottom();
  141. for (auto* child : visible_children) {
  142. // Most recent apps be added to the left and shift right as the other apps
  143. // are streamed.
  144. int width = child->GetPreferredSize().width();
  145. child->SetBounds(child_x, child_y, width, child->GetHeightForWidth(width));
  146. child_x += width + spacing;
  147. }
  148. }
  149. const char* PhoneHubRecentAppsView::RecentAppButtonsView::GetClassName() const {
  150. return "RecentAppButtonView";
  151. }
  152. void PhoneHubRecentAppsView::RecentAppButtonsView::Reset() {
  153. RemoveAllChildViews();
  154. }
  155. void PhoneHubRecentAppsView::Update() {
  156. recent_app_buttons_view_->Reset();
  157. recent_app_button_list_.clear();
  158. RecentAppsUiState current_ui_state =
  159. recent_apps_interaction_handler_->ui_state();
  160. switch (current_ui_state) {
  161. case RecentAppsUiState::HIDDEN:
  162. placeholder_view_->SetVisible(false);
  163. SetVisible(false);
  164. break;
  165. case RecentAppsUiState::PLACEHOLDER_VIEW:
  166. recent_app_buttons_view_->SetVisible(false);
  167. placeholder_view_->SetVisible(true);
  168. SetVisible(true);
  169. break;
  170. case RecentAppsUiState::ITEMS_VISIBLE:
  171. std::vector<phonehub::Notification::AppMetadata> recent_apps_list =
  172. recent_apps_interaction_handler_->FetchRecentAppMetadataList();
  173. for (const auto& recent_app : recent_apps_list) {
  174. auto pressed_callback = base::BindRepeating(
  175. &phonehub::RecentAppsInteractionHandler::NotifyRecentAppClicked,
  176. base::Unretained(recent_apps_interaction_handler_), recent_app);
  177. recent_app_button_list_.push_back(
  178. recent_app_buttons_view_->AddRecentAppButton(
  179. std::make_unique<PhoneHubRecentAppButton>(
  180. recent_app.icon, recent_app.visible_app_name,
  181. pressed_callback)));
  182. }
  183. recent_app_buttons_view_->SetVisible(true);
  184. placeholder_view_->SetVisible(false);
  185. SetVisible(true);
  186. break;
  187. }
  188. PreferredSizeChanged();
  189. }
  190. } // namespace ash