Add unified GlanceablesListFooterView
This view is shared between classroom student, classroom teacher and tasks bubbles. It displays "Showing X out of Y" test and "See all" button. Low-Coverage-Reason: Added *::OnSeeAllPressed() are NOTIMPLEMENTED(). Bug: b/283370862 Change-Id: I1096fed1b9cf781122bfd5be71c02ab801b464b6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4662135 Reviewed-by: Toni Barzic <tbarzic@chromium.org> Commit-Queue: Artsiom Mitrokhin <amitrokhin@chromium.org> Cr-Commit-Position: refs/heads/main@{#1166548}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f0fca50a5e
commit
0adbb3cb1a
@ -618,6 +618,9 @@ component("ash") {
|
||||
"glanceables/classroom/glanceables_classroom_item_view.h",
|
||||
"glanceables/classroom/glanceables_classroom_types.cc",
|
||||
"glanceables/classroom/glanceables_classroom_types.h",
|
||||
"glanceables/common/glanceables_list_footer_view.cc",
|
||||
"glanceables/common/glanceables_list_footer_view.h",
|
||||
"glanceables/common/glanceables_view_id.h",
|
||||
"glanceables/glanceables_controller.cc",
|
||||
"glanceables/glanceables_controller.h",
|
||||
"glanceables/glanceables_delegate.h",
|
||||
|
@ -6717,10 +6717,10 @@ New install
|
||||
<message name="IDS_GLANCEABLES_WELCOME_LABEL" desc="Personalized greeting / welcome message shown on glanceables surfaces (welcome screen and overview mode).">
|
||||
Welcome back, <ph name="GIVEN_NAME">$1<ex>John</ex></ph>
|
||||
</message>
|
||||
<message name="IDS_GLANCEABLES_TASKS_DETAILS_FOOTER" desc="The glanceable displays tasks from a task list that's selected in a drop-down box within the glanceable UI. The first placeholder value is the number of tasks visible in the UI. The second placeholder value is the total number of tasks in the selected tasks list, including tasks that are not visible in the UI.">
|
||||
Showing <ph name="NUM_SHOWN_TASKS">$1<ex>5</ex></ph> out of <ph name="NUM_TOTAL_TASKS">$2<ex>10</ex></ph>
|
||||
<message name="IDS_GLANCEABLES_LIST_FOOTER_ITEMS_COUNT_LABEL" desc="The glanceable displays classroom or tasks items fetched from Google Classroom or Google Tasks API. The first placeholder value is the number of items visible in the UI. The second placeholder value is the total number of items returned from API.">
|
||||
Showing <ph name="NUM_SHOWN_ITEMS">$1<ex>5</ex></ph> out of <ph name="NUM_TOTAL_ITEMS">$2<ex>10</ex></ph>
|
||||
</message>
|
||||
<message name="IDS_GLANCEABLES_TASKS_ACTION_BUTTON_LABEL" desc="The glanceable displays tasks from a task list that's selected in a drop-down box within the glanceable UI. Interacting with the button and label at the bottom of the glanceable opens the Tasks companion app.">
|
||||
<message name="IDS_GLANCEABLES_LIST_FOOTER_ACTION_BUTTON_LABEL" desc="The glanceable displays classroom or tasks items fetched from Google Classroom or Google Tasks API. Glanceables UI renders only limited number of items, the rest of them can be seen by clicking this button, which will open a corresponding website.">
|
||||
See all
|
||||
</message>
|
||||
<message name="IDS_GLANCEABLES_CLASSROOM_ASSIGNMENT_DUE_TODAY" desc="Classroom glanceable displays upcoming/missed/completed assignments from Google Classroom. This text is displayed for assignments that are due today. In other cases date formatter is used and no translation is needed.">
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_client.h"
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_types.h"
|
||||
#include "ash/glanceables/common/glanceables_view_id.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
@ -20,6 +21,7 @@
|
||||
#include "base/i18n/time_formatting.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/cxx23_to_underlying.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/metadata/metadata_impl_macros.h"
|
||||
#include "ui/base/models/image_model.h"
|
||||
@ -99,7 +101,7 @@ std::unique_ptr<views::ImageView> BuildIcon() {
|
||||
return views::Builder<views::ImageView>()
|
||||
.SetBackground(views::CreateThemedRoundedRectBackground(
|
||||
cros_tokens::kCrosSysSystemOnBase1, kIconViewBackgroundRadius))
|
||||
.SetID(GlanceablesClassroomItemView::kIconViewId)
|
||||
.SetID(base::to_underlying(GlanceablesViewId::kClassroomItemIcon))
|
||||
.SetImage(ui::ImageModel::FromVectorIcon(
|
||||
kGlanceablesClassroomAssignmentIcon, cros_tokens::kCrosSysOnSurface,
|
||||
kIconSize))
|
||||
@ -120,18 +122,19 @@ std::unique_ptr<views::BoxLayoutView> BuildAssignmentTitleLabels(
|
||||
views::kFlexBehaviorKey,
|
||||
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
|
||||
views::MaximumFlexSizeRule::kUnbounded))
|
||||
.AddChild(
|
||||
views::Builder<views::Label>()
|
||||
.SetText(base::UTF8ToUTF16(assignment->course_work_title))
|
||||
.SetID(GlanceablesClassroomItemView::kCourseWorkTitleLabelId)
|
||||
.SetEnabledColorId(cros_tokens::kCrosSysOnSurface)
|
||||
.SetFontList(typography_provider->ResolveTypographyToken(
|
||||
TypographyToken::kCrosButton2))
|
||||
.SetLineHeight(typography_provider->ResolveLineHeight(
|
||||
TypographyToken::kCrosButton2)))
|
||||
.AddChild(views::Builder<views::Label>()
|
||||
.SetText(base::UTF8ToUTF16(assignment->course_work_title))
|
||||
.SetID(base::to_underlying(
|
||||
GlanceablesViewId::kClassroomItemCourseWorkTitleLabel))
|
||||
.SetEnabledColorId(cros_tokens::kCrosSysOnSurface)
|
||||
.SetFontList(typography_provider->ResolveTypographyToken(
|
||||
TypographyToken::kCrosButton2))
|
||||
.SetLineHeight(typography_provider->ResolveLineHeight(
|
||||
TypographyToken::kCrosButton2)))
|
||||
.AddChild(views::Builder<views::Label>()
|
||||
.SetText(base::UTF8ToUTF16(assignment->course_title))
|
||||
.SetID(GlanceablesClassroomItemView::kCourseTitleLabelId)
|
||||
.SetID(base::to_underlying(
|
||||
GlanceablesViewId::kClassroomItemCourseTitleLabel))
|
||||
.SetEnabledColorId(cros_tokens::kCrosSysOnSurfaceVariant)
|
||||
.SetFontList(typography_provider->ResolveTypographyToken(
|
||||
TypographyToken::kCrosAnnotation1))
|
||||
@ -151,7 +154,8 @@ std::unique_ptr<views::BoxLayoutView> BuildDueLabels(
|
||||
.SetProperty(views::kMarginsKey, kDueLabelsMargin)
|
||||
.AddChild(views::Builder<views::Label>()
|
||||
.SetText(GetFormattedDueDate(assignment->due.value()))
|
||||
.SetID(GlanceablesClassroomItemView::kDueDateLabelId)
|
||||
.SetID(base::to_underlying(
|
||||
GlanceablesViewId::kClassroomItemDueDateLabel))
|
||||
.SetEnabledColorId(cros_tokens::kCrosSysOnSurfaceVariant)
|
||||
.SetFontList(typography_provider->ResolveTypographyToken(
|
||||
TypographyToken::kCrosAnnotation1))
|
||||
@ -159,7 +163,8 @@ std::unique_ptr<views::BoxLayoutView> BuildDueLabels(
|
||||
TypographyToken::kCrosAnnotation1)))
|
||||
.AddChild(views::Builder<views::Label>()
|
||||
.SetText(GetFormattedDueTime(assignment->due.value()))
|
||||
.SetID(GlanceablesClassroomItemView::kDueTimeLabelId)
|
||||
.SetID(base::to_underlying(
|
||||
GlanceablesViewId::kClassroomItemDueTimeLabel))
|
||||
.SetEnabledColorId(cros_tokens::kCrosSysOnSurfaceVariant)
|
||||
.SetFontList(typography_provider->ResolveTypographyToken(
|
||||
TypographyToken::kCrosAnnotation1))
|
||||
|
@ -19,13 +19,6 @@ class ASH_EXPORT GlanceablesClassroomItemView : public views::FlexLayoutView {
|
||||
public:
|
||||
METADATA_HEADER(GlanceablesClassroomItemView);
|
||||
|
||||
// Known view ids.
|
||||
static constexpr int kIconViewId = 1;
|
||||
static constexpr int kCourseWorkTitleLabelId = 2;
|
||||
static constexpr int kCourseTitleLabelId = 3;
|
||||
static constexpr int kDueDateLabelId = 4;
|
||||
static constexpr int kDueTimeLabelId = 5;
|
||||
|
||||
explicit GlanceablesClassroomItemView(
|
||||
const GlanceablesClassroomStudentAssignment* assignment);
|
||||
GlanceablesClassroomItemView(const GlanceablesClassroomItemView&) = delete;
|
||||
|
@ -8,12 +8,14 @@
|
||||
#include <vector>
|
||||
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_types.h"
|
||||
#include "ash/glanceables/common/glanceables_view_id.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/system/model/system_tray_model.h"
|
||||
#include "ash/system/time/calendar_unittest_utils.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/time/time_override.h"
|
||||
#include "base/types/cxx23_to_underlying.h"
|
||||
#include "chromeos/ash/components/settings/scoped_timezone_settings.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "ui/views/controls/image_view.h"
|
||||
@ -27,32 +29,34 @@ class GlanceablesClassroomItemViewTest : public AshTestBase {
|
||||
public:
|
||||
const views::ImageView* GetIconView(
|
||||
const GlanceablesClassroomItemView& view) const {
|
||||
return views::AsViewClass<views::ImageView>(
|
||||
view.GetViewByID(GlanceablesClassroomItemView::kIconViewId));
|
||||
return views::AsViewClass<views::ImageView>(view.GetViewByID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomItemIcon)));
|
||||
}
|
||||
|
||||
const views::Label* GetCourseWorkTitleLabel(
|
||||
const GlanceablesClassroomItemView& view) const {
|
||||
return views::AsViewClass<views::Label>(view.GetViewByID(
|
||||
GlanceablesClassroomItemView::kCourseWorkTitleLabelId));
|
||||
return views::AsViewClass<views::Label>(
|
||||
view.GetViewByID(base::to_underlying(
|
||||
GlanceablesViewId::kClassroomItemCourseWorkTitleLabel)));
|
||||
}
|
||||
|
||||
const views::Label* GetCourseTitleLabel(
|
||||
const GlanceablesClassroomItemView& view) const {
|
||||
return views::AsViewClass<views::Label>(
|
||||
view.GetViewByID(GlanceablesClassroomItemView::kCourseTitleLabelId));
|
||||
view.GetViewByID(base::to_underlying(
|
||||
GlanceablesViewId::kClassroomItemCourseTitleLabel)));
|
||||
}
|
||||
|
||||
const views::Label* GetDueDateLabel(
|
||||
const GlanceablesClassroomItemView& view) const {
|
||||
return views::AsViewClass<views::Label>(
|
||||
view.GetViewByID(GlanceablesClassroomItemView::kDueDateLabelId));
|
||||
return views::AsViewClass<views::Label>(view.GetViewByID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomItemDueDateLabel)));
|
||||
}
|
||||
|
||||
const views::Label* GetDueTimeLabel(
|
||||
const GlanceablesClassroomItemView& view) const {
|
||||
return views::AsViewClass<views::Label>(
|
||||
view.GetViewByID(GlanceablesClassroomItemView::kDueTimeLabelId));
|
||||
return views::AsViewClass<views::Label>(view.GetViewByID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomItemDueTimeLabel)));
|
||||
}
|
||||
};
|
||||
|
||||
|
91
ash/glanceables/common/glanceables_list_footer_view.cc
Normal file
91
ash/glanceables/common/glanceables_list_footer_view.cc
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/glanceables/common/glanceables_list_footer_view.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "ash/glanceables/common/glanceables_view_id.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/style/typography.h"
|
||||
#include "base/check_op.h"
|
||||
#include "base/functional/callback_forward.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/types/cxx23_to_underlying.h"
|
||||
#include "components/vector_icons/vector_icons.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/metadata/metadata_impl_macros.h"
|
||||
#include "ui/base/models/image_model.h"
|
||||
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
|
||||
#include "ui/gfx/text_constants.h"
|
||||
#include "ui/views/controls/button/button.h"
|
||||
#include "ui/views/controls/button/label_button.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
#include "ui/views/layout/flex_layout_types.h"
|
||||
#include "ui/views/layout/layout_types.h"
|
||||
#include "ui/views/metadata/view_factory_internal.h"
|
||||
#include "ui/views/view.h"
|
||||
#include "ui/views/view_class_properties.h"
|
||||
|
||||
namespace ash {
|
||||
namespace {
|
||||
|
||||
constexpr int kSeeAllIconSize = 24;
|
||||
|
||||
} // namespace
|
||||
|
||||
GlanceablesListFooterView::GlanceablesListFooterView(
|
||||
base::RepeatingClosure on_see_all_pressed) {
|
||||
SetCrossAxisAlignment(views::LayoutAlignment::kCenter);
|
||||
|
||||
const auto* const typography_provider = TypographyProvider::Get();
|
||||
|
||||
items_count_label_ = AddChildView(
|
||||
views::Builder<views::Label>()
|
||||
.SetID(base::to_underlying(
|
||||
GlanceablesViewId::kListFooterItemsCountLabel))
|
||||
.SetEnabledColorId(cros_tokens::kCrosSysSecondary)
|
||||
.SetFontList(typography_provider->ResolveTypographyToken(
|
||||
TypographyToken::kCrosBody2))
|
||||
.SetLineHeight(typography_provider->ResolveLineHeight(
|
||||
TypographyToken::kCrosBody2))
|
||||
.SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
|
||||
.SetProperty(
|
||||
views::kFlexBehaviorKey,
|
||||
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
|
||||
views::MaximumFlexSizeRule::kUnbounded))
|
||||
.Build());
|
||||
|
||||
auto* const see_all_button =
|
||||
AddChildView(views::Builder<views::LabelButton>()
|
||||
.SetText(l10n_util::GetStringUTF16(
|
||||
IDS_GLANCEABLES_LIST_FOOTER_ACTION_BUTTON_LABEL))
|
||||
.SetCallback(std::move(on_see_all_pressed))
|
||||
.SetID(base::to_underlying(
|
||||
GlanceablesViewId::kListFooterSeeAllButton))
|
||||
.Build());
|
||||
see_all_button->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_RIGHT);
|
||||
see_all_button->SetImageModel(
|
||||
views::Button::STATE_NORMAL,
|
||||
ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon,
|
||||
cros_tokens::kCrosSysOnSurface,
|
||||
kSeeAllIconSize));
|
||||
see_all_button->SetTextColorId(views::Button::STATE_NORMAL,
|
||||
cros_tokens::kCrosSysOnSurface);
|
||||
}
|
||||
|
||||
void GlanceablesListFooterView::UpdateItemsCount(size_t visible_items_count,
|
||||
size_t total_items_count) {
|
||||
CHECK_LE(visible_items_count, total_items_count);
|
||||
items_count_label_->SetText(
|
||||
l10n_util::GetStringFUTF16(IDS_GLANCEABLES_LIST_FOOTER_ITEMS_COUNT_LABEL,
|
||||
base::NumberToString16(visible_items_count),
|
||||
base::NumberToString16(total_items_count)));
|
||||
}
|
||||
|
||||
BEGIN_METADATA(GlanceablesListFooterView, views::View)
|
||||
END_METADATA
|
||||
|
||||
} // namespace ash
|
43
ash/glanceables/common/glanceables_list_footer_view.h
Normal file
43
ash/glanceables/common/glanceables_list_footer_view.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ASH_GLANCEABLES_COMMON_GLANCEABLES_LIST_FOOTER_VIEW_H_
|
||||
#define ASH_GLANCEABLES_COMMON_GLANCEABLES_LIST_FOOTER_VIEW_H_
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "base/allocator/partition_allocator/pointers/raw_ptr.h"
|
||||
#include "base/functional/callback_forward.h"
|
||||
#include "ui/base/metadata/metadata_header_macros.h"
|
||||
#include "ui/views/layout/flex_layout_view.h"
|
||||
|
||||
namespace views {
|
||||
class Label;
|
||||
} // namespace views
|
||||
|
||||
namespace ash {
|
||||
|
||||
// Renders "Showing X out of Y" label and "See all" button. Used in classroom
|
||||
// and tasks bubbles.
|
||||
class ASH_EXPORT GlanceablesListFooterView : public views::FlexLayoutView {
|
||||
public:
|
||||
METADATA_HEADER(GlanceablesListFooterView);
|
||||
|
||||
explicit GlanceablesListFooterView(base::RepeatingClosure on_see_all_pressed);
|
||||
GlanceablesListFooterView(const GlanceablesListFooterView&) = delete;
|
||||
GlanceablesListFooterView& operator=(const GlanceablesListFooterView&) =
|
||||
delete;
|
||||
~GlanceablesListFooterView() override = default;
|
||||
|
||||
// Updates `items_count_label_`.
|
||||
// `visible_items_count` - number of items visible/rendered in a list.
|
||||
// `total_items_count` - total number of items returned from API.
|
||||
void UpdateItemsCount(size_t visible_items_count, size_t total_items_count);
|
||||
|
||||
private:
|
||||
raw_ptr<views::Label, ExperimentalAsh> items_count_label_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_GLANCEABLES_COMMON_GLANCEABLES_LIST_FOOTER_VIEW_H_
|
33
ash/glanceables/common/glanceables_view_id.h
Normal file
33
ash/glanceables/common/glanceables_view_id.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ASH_GLANCEABLES_COMMON_GLANCEABLES_VIEW_ID_H_
|
||||
#define ASH_GLANCEABLES_COMMON_GLANCEABLES_VIEW_ID_H_
|
||||
|
||||
namespace ash {
|
||||
|
||||
// Known view ids assigned to glanceables views to query them in tests.
|
||||
enum class GlanceablesViewId {
|
||||
kDefaultIdZero,
|
||||
|
||||
// `GlanceablesListFooterView`.
|
||||
kListFooterItemsCountLabel,
|
||||
kListFooterSeeAllButton,
|
||||
|
||||
// `ClassroomBubbleBaseView`.
|
||||
kClassroomBubbleComboBox,
|
||||
kClassroomBubbleListContainer,
|
||||
kClassroomBubbleListFooter,
|
||||
|
||||
// `GlanceablesClassroomItemView`.
|
||||
kClassroomItemIcon,
|
||||
kClassroomItemCourseWorkTitleLabel,
|
||||
kClassroomItemCourseTitleLabel,
|
||||
kClassroomItemDueDateLabel,
|
||||
kClassroomItemDueTimeLabel,
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_GLANCEABLES_COMMON_GLANCEABLES_VIEW_ID_H_
|
@ -6,7 +6,11 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/glanceables/common/glanceables_list_footer_view.h"
|
||||
#include "ash/glanceables/common/glanceables_view_id.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/types/cxx23_to_underlying.h"
|
||||
#include "ui/base/metadata/metadata_impl_macros.h"
|
||||
#include "ui/base/models/combobox_model.h"
|
||||
#include "ui/base/models/image_model.h"
|
||||
@ -51,14 +55,16 @@ ClassroomBubbleBaseView::ClassroomBubbleBaseView(
|
||||
|
||||
combo_box_view_ = header_view_->AddChildView(
|
||||
std::make_unique<views::Combobox>(std::move(combobox_model)));
|
||||
combo_box_view_->SetID(kComboBoxViewId);
|
||||
combo_box_view_->SetID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomBubbleComboBox));
|
||||
combo_box_view_->SetSelectedIndex(0);
|
||||
// TODO(b:283370907): Implement accessibility behavior.
|
||||
combo_box_view_->SetTooltipTextAndAccessibleName(u"Assignment list selector");
|
||||
|
||||
list_container_view_ =
|
||||
AddChildView(std::make_unique<views::FlexLayoutView>());
|
||||
list_container_view_->SetID(kListContainerViewId);
|
||||
list_container_view_->SetID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomBubbleListContainer));
|
||||
list_container_view_->SetOrientation(views::LayoutOrientation::kVertical);
|
||||
list_container_view_->SetPaintToLayer();
|
||||
list_container_view_->layer()->SetFillsBoundsOpaquely(false);
|
||||
@ -67,6 +73,12 @@ ClassroomBubbleBaseView::ClassroomBubbleBaseView(
|
||||
list_container_view_->SetProperty(
|
||||
views::kMarginsKey,
|
||||
gfx::Insets::TLBR(kSpacingAboveListContainerView, 0, 0, 0));
|
||||
|
||||
list_footer_view_ = AddChildView(
|
||||
std::make_unique<GlanceablesListFooterView>(base::BindRepeating(
|
||||
&ClassroomBubbleBaseView::OnSeeAllPressed, base::Unretained(this))));
|
||||
list_footer_view_->SetID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomBubbleListFooter));
|
||||
}
|
||||
|
||||
ClassroomBubbleBaseView::~ClassroomBubbleBaseView() = default;
|
||||
|
@ -19,31 +19,34 @@ class ComboboxModel;
|
||||
|
||||
namespace ash {
|
||||
|
||||
class GlanceablesListFooterView;
|
||||
|
||||
class ASH_EXPORT ClassroomBubbleBaseView : public GlanceableTrayChildBubble {
|
||||
public:
|
||||
METADATA_HEADER(ClassroomBubbleBaseView);
|
||||
|
||||
// Known view ids.
|
||||
static constexpr int kComboBoxViewId = 1;
|
||||
static constexpr int kListContainerViewId = 2;
|
||||
|
||||
// TODO(b:283370907): Add classroom glanceable contents.
|
||||
explicit ClassroomBubbleBaseView(
|
||||
DetailedViewDelegate* delegate,
|
||||
std::unique_ptr<ui::ComboboxModel> combobox_model);
|
||||
ClassroomBubbleBaseView(DetailedViewDelegate* delegate,
|
||||
std::unique_ptr<ui::ComboboxModel> combobox_model);
|
||||
ClassroomBubbleBaseView(const ClassroomBubbleBaseView&) = delete;
|
||||
ClassroomBubbleBaseView& operator-(const ClassroomBubbleBaseView&) = delete;
|
||||
ClassroomBubbleBaseView& operator=(const ClassroomBubbleBaseView&) = delete;
|
||||
~ClassroomBubbleBaseView() override;
|
||||
|
||||
// views::View:
|
||||
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
|
||||
|
||||
protected:
|
||||
// Handles press on the "See all" button in `GlanceablesListFooterView`. Opens
|
||||
// classroom web UI based on the selected menu option.
|
||||
virtual void OnSeeAllPressed() = 0;
|
||||
|
||||
// Owned by views hierarchy.
|
||||
raw_ptr<views::FlexLayoutView, ExperimentalAsh> header_view_ = nullptr;
|
||||
raw_ptr<views::Combobox, ExperimentalAsh> combo_box_view_ = nullptr;
|
||||
raw_ptr<views::FlexLayoutView, ExperimentalAsh> list_container_view_ =
|
||||
nullptr;
|
||||
raw_ptr<GlanceablesListFooterView, ExperimentalAsh> list_footer_view_ =
|
||||
nullptr;
|
||||
|
||||
base::WeakPtrFactory<ClassroomBubbleBaseView> weak_ptr_factory_{this};
|
||||
};
|
||||
|
@ -11,11 +11,13 @@
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_client.h"
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_item_view.h"
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_types.h"
|
||||
#include "ash/glanceables/common/glanceables_list_footer_view.h"
|
||||
#include "ash/glanceables/glanceables_v2_controller.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/system/tray/detailed_view_delegate.h"
|
||||
#include "base/check.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/notreached.h"
|
||||
#include "base/strings/string_piece_forward.h"
|
||||
#include "ui/gfx/geometry/insets.h"
|
||||
#include "ui/views/controls/combobox/combobox.h"
|
||||
@ -91,6 +93,10 @@ ClassroomBubbleStudentView::ClassroomBubbleStudentView(
|
||||
|
||||
ClassroomBubbleStudentView::~ClassroomBubbleStudentView() = default;
|
||||
|
||||
void ClassroomBubbleStudentView::OnSeeAllPressed() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ClassroomBubbleStudentView::OnGetStudentAssignments(
|
||||
std::vector<std::unique_ptr<GlanceablesClassroomStudentAssignment>>
|
||||
assignments) {
|
||||
@ -112,6 +118,9 @@ void ClassroomBubbleStudentView::OnGetStudentAssignments(
|
||||
list_container_view_->children().back()->SetProperty(views::kMarginsKey,
|
||||
gfx::Insets());
|
||||
}
|
||||
|
||||
list_footer_view_->UpdateItemsCount(list_container_view_->children().size(),
|
||||
assignments.size());
|
||||
}
|
||||
|
||||
void ClassroomBubbleStudentView::SelectedAssignmentListChanged() {
|
||||
|
@ -20,6 +20,10 @@ class ASH_EXPORT ClassroomBubbleStudentView : public ClassroomBubbleBaseView {
|
||||
delete;
|
||||
~ClassroomBubbleStudentView() override;
|
||||
|
||||
private:
|
||||
// ClassroomBubbleBaseView:
|
||||
void OnSeeAllPressed() override;
|
||||
|
||||
// Handle switching between assignment lists.
|
||||
void SelectedAssignmentListChanged();
|
||||
|
||||
|
@ -11,11 +11,13 @@
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_client.h"
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_item_view.h"
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_types.h"
|
||||
#include "ash/glanceables/common/glanceables_list_footer_view.h"
|
||||
#include "ash/glanceables/glanceables_v2_controller.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/system/tray/detailed_view_delegate.h"
|
||||
#include "base/check.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/notreached.h"
|
||||
#include "base/strings/string_piece_forward.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "ui/gfx/geometry/insets.h"
|
||||
@ -92,6 +94,10 @@ ClassroomBubbleTeacherView::ClassroomBubbleTeacherView(
|
||||
|
||||
ClassroomBubbleTeacherView::~ClassroomBubbleTeacherView() = default;
|
||||
|
||||
void ClassroomBubbleTeacherView::OnSeeAllPressed() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ClassroomBubbleTeacherView::OnGetTeacherAssignments(
|
||||
std::vector<std::unique_ptr<GlanceablesClassroomTeacherAssignment>>
|
||||
assignments) {
|
||||
@ -113,6 +119,9 @@ void ClassroomBubbleTeacherView::OnGetTeacherAssignments(
|
||||
list_container_view_->children().back()->SetProperty(views::kMarginsKey,
|
||||
gfx::Insets());
|
||||
}
|
||||
|
||||
list_footer_view_->UpdateItemsCount(list_container_view_->children().size(),
|
||||
assignments.size());
|
||||
}
|
||||
|
||||
void ClassroomBubbleTeacherView::SelectedAssignmentListChanged() {
|
||||
|
@ -19,6 +19,10 @@ class ASH_EXPORT ClassroomBubbleTeacherView : public ClassroomBubbleBaseView {
|
||||
delete;
|
||||
~ClassroomBubbleTeacherView() override;
|
||||
|
||||
private:
|
||||
// ClassroomBubbleBaseView:
|
||||
void OnSeeAllPressed() override;
|
||||
|
||||
// Handle switching between assignment lists.
|
||||
void SelectedAssignmentListChanged();
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_client.h"
|
||||
#include "ash/glanceables/classroom/glanceables_classroom_types.h"
|
||||
#include "ash/glanceables/common/glanceables_list_footer_view.h"
|
||||
#include "ash/glanceables/common/glanceables_view_id.h"
|
||||
#include "ash/glanceables/glanceables_v2_controller.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/system/tray/detailed_view_delegate.h"
|
||||
@ -19,11 +21,13 @@
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/types/cxx23_to_underlying.h"
|
||||
#include "components/account_id/account_id.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "ui/views/controls/combobox/combobox.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
#include "ui/views/view.h"
|
||||
#include "ui/views/view_utils.h"
|
||||
#include "url/gurl.h"
|
||||
@ -94,13 +98,18 @@ class ClassroomBubbleViewTest : public AshTestBase {
|
||||
}
|
||||
|
||||
views::Combobox* GetComboBoxView() {
|
||||
return views::AsViewClass<views::Combobox>(
|
||||
view_->GetViewByID(ClassroomBubbleBaseView::kComboBoxViewId));
|
||||
return views::AsViewClass<views::Combobox>(view_->GetViewByID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomBubbleComboBox)));
|
||||
}
|
||||
|
||||
const views::View* GetListContainerView() const {
|
||||
return views::AsViewClass<views::View>(
|
||||
view_->GetViewByID(ClassroomBubbleBaseView::kListContainerViewId));
|
||||
return views::AsViewClass<views::View>(view_->GetViewByID(
|
||||
base::to_underlying(GlanceablesViewId::kClassroomBubbleListContainer)));
|
||||
}
|
||||
|
||||
const views::Label* GetListFooterItemsCountLabel() const {
|
||||
return views::AsViewClass<views::Label>(view_->GetViewByID(
|
||||
base::to_underlying(GlanceablesViewId::kListFooterItemsCountLabel)));
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -245,6 +254,9 @@ TEST_F(ClassroomBubbleStudentViewTest, RendersListItems) {
|
||||
|
||||
GetComboBoxView()->MenuSelectionAt(3);
|
||||
EXPECT_EQ(GetListContainerView()->children().size(), 3u); // No more than 3.
|
||||
|
||||
ASSERT_TRUE(GetListFooterItemsCountLabel());
|
||||
EXPECT_EQ(GetListFooterItemsCountLabel()->GetText(), u"Showing 3 out of 5");
|
||||
}
|
||||
|
||||
TEST_F(ClassroomBubbleTeacherViewTest, RendersListItems) {
|
||||
@ -269,6 +281,9 @@ TEST_F(ClassroomBubbleTeacherViewTest, RendersListItems) {
|
||||
|
||||
GetComboBoxView()->MenuSelectionAt(3);
|
||||
EXPECT_EQ(GetListContainerView()->children().size(), 3u); // No more than 3.
|
||||
|
||||
ASSERT_TRUE(GetListFooterItemsCountLabel());
|
||||
EXPECT_EQ(GetListFooterItemsCountLabel()->GetText(), u"Showing 3 out of 5");
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -5,26 +5,21 @@
|
||||
#include "ash/system/unified/tasks_bubble_view.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "ash/glanceables/common/glanceables_list_footer_view.h"
|
||||
#include "ash/glanceables/glanceables_v2_controller.h"
|
||||
#include "ash/glanceables/tasks/glanceables_task_view.h"
|
||||
#include "ash/glanceables/tasks/glanceables_tasks_client.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/style/ash_color_id.h"
|
||||
#include "ash/style/icon_button.h"
|
||||
#include "ash/system/tray/tray_constants.h"
|
||||
#include "ash/system/unified/glanceable_tray_child_bubble.h"
|
||||
#include "ash/system/unified/tasks_combobox_model.h"
|
||||
#include "chromeos/constants/chromeos_features.h"
|
||||
#include "components/vector_icons/vector_icons.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/metadata/metadata_impl_macros.h"
|
||||
#include "ui/views/accessibility/view_accessibility.h"
|
||||
#include "ui/views/controls/button/label_button.h"
|
||||
#include "ui/views/controls/combobox/combobox.h"
|
||||
#include "ui/views/controls/image_view.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
#include "ui/views/layout/flex_layout_view.h"
|
||||
#include "ui/views/vector_icons.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -34,8 +29,6 @@ constexpr int kGlanceablesTaskViewHeight = 48;
|
||||
constexpr int kGlanceablesTaskFooterHeight = 24;
|
||||
constexpr int kGlanceablesFooterMargin = 12;
|
||||
constexpr int kGlanceableTaskVerticalMargin = 2;
|
||||
constexpr int kGlanceablesActionButtonLeftRightMargin = 4;
|
||||
constexpr int kIconSize = 24;
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -130,67 +123,9 @@ void TasksBubbleView::InitViews(ui::ListModel<GlanceablesTaskList>* task_list) {
|
||||
&TasksBubbleView::SelectedTasksListChanged, base::Unretained(this)));
|
||||
task_list_combo_box_view_->SetSelectedIndex(0);
|
||||
|
||||
tasks_footer_view_ = AddChildView(std::make_unique<views::FlexLayoutView>());
|
||||
tasks_footer_view_->SetCrossAxisAlignment(views::LayoutAlignment::kCenter);
|
||||
tasks_footer_view_->SetMainAxisAlignment(views::LayoutAlignment::kStart);
|
||||
tasks_footer_view_->SetOrientation(views::LayoutOrientation::kHorizontal);
|
||||
tasks_footer_view_->SetProperty(
|
||||
views::kFlexBehaviorKey,
|
||||
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
|
||||
views::MaximumFlexSizeRule::kPreferred)
|
||||
.WithOrder(1));
|
||||
|
||||
tasks_bubble_details_ =
|
||||
tasks_footer_view_->AddChildView(std::make_unique<views::Label>());
|
||||
tasks_bubble_details_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
|
||||
// Views should not be individually selected for accessibility. Accessible
|
||||
// name and behavior comes from the parent.
|
||||
tasks_bubble_details_->GetViewAccessibility().OverrideIsIgnored(true);
|
||||
tasks_bubble_details_->SetBackgroundColor(SK_ColorTRANSPARENT);
|
||||
tasks_bubble_details_->SetAutoColorReadabilityEnabled(false);
|
||||
if (chromeos::features::IsJellyEnabled()) {
|
||||
tasks_bubble_details_->SetEnabledColorId(cros_tokens::kCrosSysSecondary);
|
||||
} else {
|
||||
tasks_bubble_details_->SetEnabledColorId(kColorAshTextColorSecondary);
|
||||
}
|
||||
|
||||
// Create a transparent separator to push `action_button_` to the right-most
|
||||
// corner of the tasks_header_view_.
|
||||
separator_ =
|
||||
tasks_footer_view_->AddChildView(std::make_unique<views::View>());
|
||||
separator_->SetPreferredSize((gfx::Size(kRevampedTrayMenuWidth, 1)));
|
||||
separator_->SetProperty(
|
||||
views::kFlexBehaviorKey,
|
||||
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
|
||||
views::MaximumFlexSizeRule::kPreferred)
|
||||
.WithOrder(2));
|
||||
|
||||
action_button_ =
|
||||
tasks_footer_view_->AddChildView(std::make_unique<views::LabelButton>(
|
||||
base::BindRepeating(&TasksBubbleView::ActionButtonPressed,
|
||||
base::Unretained(this)),
|
||||
l10n_util::GetStringUTF16(
|
||||
IDS_GLANCEABLES_TASKS_ACTION_BUTTON_LABEL)));
|
||||
action_button_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
|
||||
action_button_->SetBorder(views::CreateEmptyBorder(
|
||||
gfx::Insets::VH(0, kGlanceablesActionButtonLeftRightMargin)));
|
||||
|
||||
if (chromeos::features::IsJellyEnabled()) {
|
||||
action_button_->SetTextColorId(views::Button::STATE_NORMAL,
|
||||
cros_tokens::kCrosSysOnSurface);
|
||||
action_button_->SetImageModel(
|
||||
views::Button::STATE_NORMAL,
|
||||
ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon,
|
||||
cros_tokens::kCrosSysOnSurface,
|
||||
kIconSize));
|
||||
} else {
|
||||
action_button_->SetTextColorId(views::Button::STATE_NORMAL,
|
||||
kColorAshTextColorPrimary);
|
||||
action_button_->SetImageModel(
|
||||
views::Button::STATE_NORMAL,
|
||||
ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon,
|
||||
kColorAshTextColorPrimary, kIconSize));
|
||||
}
|
||||
list_footer_view_ = AddChildView(
|
||||
std::make_unique<GlanceablesListFooterView>(base::BindRepeating(
|
||||
&TasksBubbleView::ActionButtonPressed, base::Unretained(this))));
|
||||
|
||||
ScheduleUpdateTasksList();
|
||||
}
|
||||
@ -236,10 +171,7 @@ void TasksBubbleView::UpdateTasksList(const std::string& task_list_id,
|
||||
++num_tasks_;
|
||||
}
|
||||
|
||||
tasks_bubble_details_->SetText(
|
||||
l10n_util::GetStringFUTF16(IDS_GLANCEABLES_TASKS_DETAILS_FOOTER,
|
||||
base::NumberToString16(num_tasks_shown_),
|
||||
base::NumberToString16(num_tasks_)));
|
||||
list_footer_view_->UpdateItemsCount(num_tasks_shown_, num_tasks_);
|
||||
}
|
||||
|
||||
BEGIN_METADATA(TasksBubbleView, views::View)
|
||||
|
@ -6,26 +6,21 @@
|
||||
#define ASH_SYSTEM_UNIFIED_TASKS_BUBBLE_VIEW_H_
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "ash/glanceables/tasks/glanceables_task_view.h"
|
||||
#include "ash/glanceables/tasks/glanceables_tasks_types.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/system/unified/glanceable_tray_child_bubble.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/metadata/metadata_header_macros.h"
|
||||
#include "ui/base/models/list_model.h"
|
||||
#include "ui/views/controls/button/image_button.h"
|
||||
#include "ui/views/layout/flex_layout_view.h"
|
||||
#include "ui/views/metadata/view_factory.h"
|
||||
|
||||
namespace views {
|
||||
class Combobox;
|
||||
class ImageView;
|
||||
class Label;
|
||||
class LabelButton;
|
||||
} // namespace views
|
||||
|
||||
namespace ash {
|
||||
|
||||
class GlanceablesListFooterView;
|
||||
class TasksComboboxModel;
|
||||
|
||||
// 'TasksBubbleView' uses nested `FlexLayoutView`s to layout the tasks bubble.
|
||||
@ -61,10 +56,7 @@ class TasksComboboxModel;
|
||||
// +----------------------------------------------------------------+
|
||||
//
|
||||
// +--------------------------------------------------------------+
|
||||
// |'tasks_footer_view_' |
|
||||
// | +-----------------------+ +-------------+ +----------------+ |
|
||||
// | |`tasks_bubble_details_`| |`separator_` | |`action_button_`| |
|
||||
// | +-----------------------+ +-------------+ +----------------+ |
|
||||
// |'list_footer_view_' |
|
||||
// +--------------------------------------------------------------+
|
||||
|
||||
class ASH_EXPORT TasksBubbleView : public GlanceableTrayChildBubble {
|
||||
@ -95,7 +87,7 @@ class ASH_EXPORT TasksBubbleView : public GlanceableTrayChildBubble {
|
||||
// Setup child views.
|
||||
void InitViews(ui::ListModel<GlanceablesTaskList>* task_list);
|
||||
|
||||
// Handles on-click behavior for `action_button_`
|
||||
// Handles on-click behavior for the "See all" button in `list_footer_view_`.
|
||||
void ActionButtonPressed();
|
||||
|
||||
// Handles switching between tasks lists.
|
||||
@ -115,12 +107,10 @@ class ASH_EXPORT TasksBubbleView : public GlanceableTrayChildBubble {
|
||||
raw_ptr<views::ImageView, ExperimentalAsh> task_icon_view_ = nullptr;
|
||||
raw_ptr<views::Combobox, ExperimentalAsh> task_list_combo_box_view_ = nullptr;
|
||||
raw_ptr<views::FlexLayoutView, ExperimentalAsh> button_container_ = nullptr;
|
||||
raw_ptr<views::FlexLayoutView, ExperimentalAsh> tasks_footer_view_ = nullptr;
|
||||
raw_ptr<views::Label, ExperimentalAsh> tasks_bubble_details_ = nullptr;
|
||||
raw_ptr<views::View, ExperimentalAsh> separator_ = nullptr;
|
||||
raw_ptr<views::LabelButton, ExperimentalAsh> action_button_ = nullptr;
|
||||
raw_ptr<views::FlexLayoutView, ExperimentalAsh> task_items_container_view_ =
|
||||
nullptr;
|
||||
raw_ptr<GlanceablesListFooterView, ExperimentalAsh> list_footer_view_ =
|
||||
nullptr;
|
||||
|
||||
base::WeakPtrFactory<TasksBubbleView> weak_ptr_factory_{this};
|
||||
};
|
||||
|
Reference in New Issue
Block a user