| // Copyright 2024 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/quick_insert/views/quick_insert_section_view.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "ash/bubble/bubble_utils.h" |
| #include "ash/quick_insert/quick_insert_asset_fetcher.h" |
| #include "ash/quick_insert/quick_insert_category.h" |
| #include "ash/quick_insert/quick_insert_search_result.h" |
| #include "ash/quick_insert/views/quick_insert_async_preview_image_view.h" |
| #include "ash/quick_insert/views/quick_insert_gif_view.h" |
| #include "ash/quick_insert/views/quick_insert_icons.h" |
| #include "ash/quick_insert/views/quick_insert_image_item_grid_view.h" |
| #include "ash/quick_insert/views/quick_insert_image_item_row_view.h" |
| #include "ash/quick_insert/views/quick_insert_image_item_view.h" |
| #include "ash/quick_insert/views/quick_insert_item_view.h" |
| #include "ash/quick_insert/views/quick_insert_item_with_submenu_view.h" |
| #include "ash/quick_insert/views/quick_insert_list_item_container_view.h" |
| #include "ash/quick_insert/views/quick_insert_list_item_view.h" |
| #include "ash/quick_insert/views/quick_insert_shortcut_hint_view.h" |
| #include "ash/quick_insert/views/quick_insert_strings.h" |
| #include "ash/quick_insert/views/quick_insert_traversable_item_container.h" |
| #include "ash/resources/vector_icons/vector_icons.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/style/typography.h" |
| #include "base/files/file_util.h" |
| #include "base/notreached.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/branding_buildflags.h" |
| #include "chromeos/ash/components/editor_menu/public/cpp/icon.h" |
| #include "chromeos/ui/base/file_icon_util.h" |
| #include "chromeos/ui/vector_icons/vector_icons.h" |
| #include "components/url_formatter/url_formatter.h" |
| #include "components/vector_icons/vector_icons.h" |
| #include "third_party/abseil-cpp/absl/functional/overload.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/chromeos/styles/cros_tokens_color_mappings.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/text_constants.h" |
| #include "ui/gfx/vector_icon_types.h" |
| #include "ui/views/accessibility/view_accessibility.h" |
| #include "ui/views/controls/button/image_button.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/controls/link.h" |
| #include "ui/views/layout/box_layout.h" |
| #include "ui/views/layout/box_layout_view.h" |
| #include "ui/views/layout/layout_manager.h" |
| #include "ui/views/layout/layout_types.h" |
| #include "ui/views/metadata/view_factory.h" |
| #include "ui/views/view_class_properties.h" |
| #include "ui/views/view_utils.h" |
| |
| namespace ash { |
| namespace { |
| |
| // Some of the icons we use do not have a default size, so we need to manually |
| // set it. |
| constexpr int kIconSize = 20; |
| |
| // Icons for browsing history should be smaller than the normal icon size. |
| constexpr auto kBrowsingHistoryIconSize = gfx::Size(18, 18); |
| |
| constexpr auto kSectionTitleMargins = gfx::Insets::VH(8, 16); |
| constexpr auto kSectionTitleTrailingLinkMargins = |
| gfx::Insets::TLBR(4, 8, 4, 16); |
| |
| QuickInsertCategory GetCategoryForEditorData( |
| const QuickInsertEditorResult& data) { |
| switch (data.mode) { |
| case QuickInsertEditorResult::Mode::kWrite: |
| return QuickInsertCategory::kEditorWrite; |
| case QuickInsertEditorResult::Mode::kRewrite: |
| return QuickInsertCategory::kEditorRewrite; |
| } |
| } |
| |
| QuickInsertCategory GetCategoryForLobsterData( |
| const QuickInsertLobsterResult& data) { |
| switch (data.mode) { |
| case QuickInsertLobsterResult::Mode::kNoSelection: |
| return QuickInsertCategory::kLobsterWithNoSelectedText; |
| case QuickInsertLobsterResult::Mode::kWithSelection: |
| return QuickInsertCategory::kLobsterWithSelectedText; |
| } |
| } |
| |
| std::u16string GetLabelForNewWindowType(QuickInsertNewWindowResult::Type type) { |
| switch (type) { |
| case QuickInsertNewWindowResult::Type::kDoc: |
| return l10n_util::GetStringUTF16(IDS_PICKER_NEW_GOOGLE_DOC_MENU_LABEL); |
| case QuickInsertNewWindowResult::Type::kSheet: |
| return l10n_util::GetStringUTF16(IDS_PICKER_NEW_GOOGLE_SHEET_MENU_LABEL); |
| case QuickInsertNewWindowResult::Type::kSlide: |
| return l10n_util::GetStringUTF16(IDS_PICKER_NEW_GOOGLE_SLIDE_MENU_LABEL); |
| case QuickInsertNewWindowResult::Type::kChrome: |
| return l10n_util::GetStringUTF16(IDS_PICKER_NEW_GOOGLE_CHROME_MENU_LABEL); |
| } |
| } |
| |
| const gfx::VectorIcon& GetIconForNewWindowType( |
| QuickInsertNewWindowResult::Type type) { |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| switch (type) { |
| case QuickInsertNewWindowResult::Type::kDoc: |
| return vector_icons::kGoogleDocsIcon; |
| case QuickInsertNewWindowResult::Type::kSheet: |
| return vector_icons::kGoogleSheetsIcon; |
| case QuickInsertNewWindowResult::Type::kSlide: |
| return vector_icons::kGoogleSlidesIcon; |
| case QuickInsertNewWindowResult::Type::kChrome: |
| return vector_icons::kProductRefreshIcon; |
| } |
| #else |
| return kPlaceholderAppIcon; |
| #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| } |
| |
| std::u16string GetLabelForCaseTransformType( |
| QuickInsertCaseTransformResult::Type type) { |
| switch (type) { |
| case QuickInsertCaseTransformResult::Type::kUpperCase: |
| return l10n_util::GetStringUTF16(IDS_PICKER_UPPER_CASE_MENU_LABEL); |
| case QuickInsertCaseTransformResult::Type::kLowerCase: |
| return l10n_util::GetStringUTF16(IDS_PICKER_LOWER_CASE_MENU_LABEL); |
| case QuickInsertCaseTransformResult::Type::kTitleCase: |
| return l10n_util::GetStringUTF16(IDS_PICKER_TITLE_CASE_MENU_LABEL); |
| } |
| } |
| |
| const gfx::VectorIcon& GetIconForCaseTransformType( |
| QuickInsertCaseTransformResult::Type type) { |
| switch (type) { |
| case QuickInsertCaseTransformResult::Type::kUpperCase: |
| return kQuickInsertUpperCaseIcon; |
| case QuickInsertCaseTransformResult::Type::kLowerCase: |
| return kQuickInsertLowerCaseIcon; |
| case QuickInsertCaseTransformResult::Type::kTitleCase: |
| return kQuickInsertTitleCaseIcon; |
| } |
| } |
| |
| std::u16string FormatBrowsingHistoryUrl(const GURL& url) { |
| return url_formatter::FormatUrl( |
| url, |
| url_formatter::kFormatUrlOmitDefaults | |
| url_formatter::kFormatUrlOmitHTTPS | |
| url_formatter::kFormatUrlOmitTrivialSubdomains, |
| base::UnescapeRule::SPACES, nullptr, nullptr, nullptr); |
| } |
| |
| std::optional<base::File::Info> ResolveFileInfo(const base::FilePath& path) { |
| base::File::Info info; |
| if (!base::GetFileInfo(path, &info)) { |
| return std::nullopt; |
| } |
| return info; |
| } |
| |
| // This should align with `chromeos::clipboard_history::GetIconForDescriptor`. |
| const gfx::VectorIcon& GetIconForClipboardData( |
| const QuickInsertClipboardResult& data) { |
| switch (data.display_format) { |
| case QuickInsertClipboardResult::DisplayFormat::kText: |
| return GURL(data.display_text).is_valid() ? vector_icons::kLinkIcon |
| : chromeos::kTextIcon; |
| case QuickInsertClipboardResult::DisplayFormat::kImage: |
| return chromeos::kFiletypeImageIcon; |
| case QuickInsertClipboardResult::DisplayFormat::kFile: |
| return data.file_count == 1 ? chromeos::GetIconForPath(base::FilePath( |
| base::UTF16ToUTF8(data.display_text))) |
| : vector_icons::kContentCopyIcon; |
| case QuickInsertClipboardResult::DisplayFormat::kHtml: |
| NOTREACHED(); |
| } |
| NOTREACHED(); |
| } |
| |
| template <typename Range> |
| auto FindContainerForItem(Range&& containers, views::View* item) { |
| return std::ranges::find_if( |
| containers, [item](QuickInsertTraversableItemContainer* container) { |
| return container->ContainsItem(item); |
| }); |
| } |
| |
| } // namespace |
| |
| QuickInsertSectionView::QuickInsertSectionView( |
| int section_width, |
| QuickInsertAssetFetcher* asset_fetcher, |
| QuickInsertSubmenuController* submenu_controller) |
| : section_width_(section_width), |
| asset_fetcher_(asset_fetcher), |
| submenu_controller_(submenu_controller) { |
| SetLayoutManager(std::make_unique<views::BoxLayout>()) |
| ->SetOrientation(views::LayoutOrientation::kVertical); |
| |
| title_container_ = |
| AddChildView(views::Builder<views::BoxLayoutView>() |
| .SetOrientation(views::LayoutOrientation::kHorizontal) |
| .Build()); |
| GetViewAccessibility().SetRole(ax::mojom::Role::kList); |
| } |
| |
| QuickInsertSectionView::~QuickInsertSectionView() = default; |
| |
| std::unique_ptr<QuickInsertItemView> |
| QuickInsertSectionView::CreateItemFromResult( |
| const QuickInsertSearchResult& result, |
| QuickInsertPreviewBubbleController* preview_controller, |
| QuickInsertAssetFetcher* asset_fetcher, |
| int available_width, |
| LocalFileResultStyle local_file_result_style, |
| SelectResultCallback select_result_callback) { |
| using ReturnType = std::unique_ptr<QuickInsertItemView>; |
| return std::visit( |
| absl::Overload{ |
| [&](const QuickInsertTextResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText(data.primary_text); |
| item_view->SetSecondaryText(data.secondary_text); |
| item_view->SetLeadingIcon(data.icon); |
| return item_view; |
| }, |
| [&](const QuickInsertSearchRequestResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText(data.primary_text); |
| item_view->SetSecondaryText(data.secondary_text); |
| item_view->SetLeadingIcon(data.icon); |
| return item_view; |
| }, |
| [&](const QuickInsertEmojiResult& data) -> ReturnType { |
| NOTREACHED(); |
| }, |
| [&](const QuickInsertClipboardResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| switch (data.display_format) { |
| case QuickInsertClipboardResult::DisplayFormat::kFile: |
| case QuickInsertClipboardResult::DisplayFormat::kText: |
| item_view->SetPrimaryText(data.display_text); |
| break; |
| case QuickInsertClipboardResult::DisplayFormat::kImage: |
| if (!data.display_image.has_value()) { |
| return nullptr; |
| } |
| item_view->SetPrimaryImage(*data.display_image, |
| available_width); |
| break; |
| case QuickInsertClipboardResult::DisplayFormat::kHtml: |
| NOTREACHED(); |
| } |
| item_view->SetLeadingIcon(ui::ImageModel::FromVectorIcon( |
| GetIconForClipboardData(data), cros_tokens::kCrosSysOnSurface, |
| kIconSize)); |
| return item_view; |
| }, |
| [&](const QuickInsertGifResult& data) -> ReturnType { |
| // `base::Unretained` is safe because `asset_fetcher` outlives the |
| // return value. |
| auto gif_view = std::make_unique<QuickInsertGifView>( |
| base::BindRepeating(&QuickInsertAssetFetcher::FetchGifFromUrl, |
| base::Unretained(asset_fetcher), |
| data.preview_url, data.rank), |
| base::BindRepeating( |
| &QuickInsertAssetFetcher::FetchGifPreviewImageFromUrl, |
| base::Unretained(asset_fetcher), data.preview_image_url, |
| data.rank), |
| data.preview_dimensions); |
| return std::make_unique<QuickInsertImageItemView>( |
| std::move(gif_view), data.content_description, |
| std::move(select_result_callback)); |
| }, |
| [&](const QuickInsertBrowsingHistoryResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| std::u16string formatted_url = FormatBrowsingHistoryUrl(data.url); |
| item_view->SetPrimaryText(data.title.empty() ? formatted_url |
| : data.title); |
| item_view->SetSecondaryText(formatted_url); |
| item_view->SetLeadingIcon(data.icon, kBrowsingHistoryIconSize); |
| return item_view; |
| }, |
| [&](const QuickInsertLocalFileResult& data) -> ReturnType { |
| switch (local_file_result_style) { |
| case LocalFileResultStyle::kList: { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText(data.title); |
| // `base::Unretained` is safe because `asset_fetcher` outlives |
| // the return value. |
| item_view->SetPreview( |
| preview_controller, |
| base::BindOnce(ResolveFileInfo, data.file_path), |
| data.file_path, |
| base::BindRepeating( |
| &QuickInsertAssetFetcher::FetchFileThumbnail, |
| base::Unretained(asset_fetcher)), |
| /*update_icon=*/true); |
| return item_view; |
| } |
| case LocalFileResultStyle::kGrid: |
| case LocalFileResultStyle::kRow: { |
| // `base::Unretained` is safe because `asset_fetcher` outlives |
| // the return value. |
| auto image_view = |
| std::make_unique<QuickInsertAsyncPreviewImageView>( |
| data.file_path, |
| gfx::Size(available_width, available_width), |
| base::BindRepeating( |
| &QuickInsertAssetFetcher::FetchFileThumbnail, |
| base::Unretained(asset_fetcher))); |
| return std::make_unique<QuickInsertImageItemView>( |
| std::move(image_view), data.title, |
| std::move(select_result_callback)); |
| } |
| } |
| }, |
| [&](const QuickInsertDriveFileResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText(data.title); |
| // TODO: b/333609460 - Handle dark/light mode. |
| item_view->SetLeadingIcon( |
| ui::ImageModel::FromImageSkia(chromeos::GetIconForPath( |
| data.file_path, /*dark_background=*/false, kIconSize))); |
| // `base::Unretained` is safe because `asset_fetcher` outlives the |
| // return value. |
| item_view->SetPreview( |
| preview_controller, |
| base::BindOnce(ResolveFileInfo, data.file_path), data.file_path, |
| base::BindRepeating( |
| &QuickInsertAssetFetcher::FetchFileThumbnail, |
| base::Unretained(asset_fetcher)), |
| /*update_icon=*/false); |
| return item_view; |
| }, |
| [&](const QuickInsertCategoryResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText( |
| GetLabelForQuickInsertCategory(data.category)); |
| item_view->SetLeadingIcon( |
| GetIconForQuickInsertCategory(data.category)); |
| return item_view; |
| }, |
| [&](const QuickInsertEditorResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| if (data.category.has_value()) { |
| // Preset write or rewrite. |
| item_view->SetPrimaryText(data.display_name); |
| item_view->SetLeadingIcon(ui::ImageModel::FromVectorIcon( |
| chromeos::editor_menu::GetIconForPresetQueryCategory( |
| *data.category), |
| cros_tokens::kCrosSysOnSurface)); |
| } else { |
| // Freeform write or rewrite. |
| const QuickInsertCategory category = |
| GetCategoryForEditorData(data); |
| item_view->SetPrimaryText( |
| GetLabelForQuickInsertCategory(category)); |
| item_view->SetLeadingIcon( |
| GetIconForQuickInsertCategory(category)); |
| } |
| return item_view; |
| }, |
| [&](const QuickInsertLobsterResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| |
| const QuickInsertCategory category = |
| GetCategoryForLobsterData(data); |
| item_view->SetPrimaryText(GetLabelForQuickInsertCategory(category)); |
| item_view->SetLeadingIcon(GetIconForQuickInsertCategory(category)); |
| return item_view; |
| }, |
| [&](const QuickInsertNewWindowResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText(GetLabelForNewWindowType(data.type)); |
| item_view->SetLeadingIcon(ui::ImageModel::FromVectorIcon( |
| GetIconForNewWindowType(data.type), |
| cros_tokens::kCrosSysOnSurface)); |
| return item_view; |
| }, |
| [&](const QuickInsertCapsLockResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText(l10n_util::GetStringUTF16( |
| data.enabled ? IDS_PICKER_CAPS_LOCK_ON_MENU_LABEL |
| : IDS_PICKER_CAPS_LOCK_OFF_MENU_LABEL)); |
| item_view->SetLeadingIcon(ui::ImageModel::FromVectorIcon( |
| data.enabled ? kQuickInsertCapsLockOnIcon |
| : kQuickInsertCapsLockOffIcon, |
| cros_tokens::kCrosSysOnSurface)); |
| item_view->SetShortcutHintView( |
| std::make_unique<QuickInsertShortcutHintView>(data.shortcut)); |
| return item_view; |
| }, |
| [&](const QuickInsertCaseTransformResult& data) -> ReturnType { |
| auto item_view = std::make_unique<QuickInsertListItemView>( |
| std::move(select_result_callback)); |
| item_view->SetPrimaryText(GetLabelForCaseTransformType(data.type)); |
| item_view->SetLeadingIcon(ui::ImageModel::FromVectorIcon( |
| GetIconForCaseTransformType(data.type), |
| cros_tokens::kCrosSysOnSurface)); |
| return item_view; |
| }, |
| }, |
| result); |
| } |
| |
| void QuickInsertSectionView::AddTitleLabel(const std::u16string& title_text) { |
| if (title_text.empty()) { |
| return; |
| } |
| |
| title_label_ = title_container_->AddChildView( |
| views::Builder<views::Label>( |
| bubble_utils::CreateLabel(TypographyToken::kCrosAnnotation2, |
| title_text, |
| cros_tokens::kCrosSysOnSurfaceVariant)) |
| .SetHorizontalAlignment(gfx::ALIGN_LEFT) |
| .SetProperty(views::kMarginsKey, kSectionTitleMargins) |
| .Build()); |
| title_label_->GetViewAccessibility().SetRole(ax::mojom::Role::kHeading); |
| title_container_->SetFlexForView(title_label_, 1); |
| } |
| |
| void QuickInsertSectionView::AddTitleTrailingLink( |
| const std::u16string& link_text, |
| const std::u16string& accessible_name, |
| views::Link::ClickedCallback link_callback) { |
| title_trailing_link_ = title_container_->AddChildView( |
| views::Builder<views::Link>() |
| .SetText(link_text) |
| .SetCallback(link_callback) |
| .SetFontList(TypographyProvider::Get()->ResolveTypographyToken( |
| TypographyToken::kCrosAnnotation2)) |
| .SetEnabledColor(cros_tokens::kCrosSysPrimary) |
| .SetForceUnderline(false) |
| .SetProperty(views::kMarginsKey, kSectionTitleTrailingLinkMargins) |
| .Build()); |
| title_trailing_link_->GetViewAccessibility().SetRole( |
| ax::mojom::Role::kButton); |
| title_trailing_link_->GetViewAccessibility().SetName(accessible_name); |
| } |
| |
| QuickInsertListItemView* QuickInsertSectionView::AddListItem( |
| std::unique_ptr<QuickInsertListItemView> list_item) { |
| list_item->SetSubmenuController(submenu_controller_); |
| QuickInsertListItemView* list_item_ptr = |
| GetOrCreateListItemContainer()->AddListItem(std::move(list_item)); |
| item_views_.push_back(list_item_ptr); |
| return list_item_ptr; |
| } |
| |
| QuickInsertImageItemView* QuickInsertSectionView::AddImageGridItem( |
| std::unique_ptr<QuickInsertImageItemView> image_item) { |
| image_item->SetSubmenuController(submenu_controller_); |
| QuickInsertImageItemView* image_item_ptr = |
| GetOrCreateImageItemGrid()->AddImageItem(std::move(image_item)); |
| item_views_.push_back(image_item_ptr); |
| return image_item_ptr; |
| } |
| |
| QuickInsertImageItemView* QuickInsertSectionView::AddImageRowItem( |
| std::unique_ptr<QuickInsertImageItemView> image_item) { |
| image_item->SetSubmenuController(submenu_controller_); |
| QuickInsertImageItemView* image_item_ptr = |
| GetOrCreateImageItemRow()->AddImageItem(std::move(image_item)); |
| item_views_.push_back(image_item_ptr); |
| return image_item_ptr; |
| } |
| |
| QuickInsertItemWithSubmenuView* QuickInsertSectionView::AddItemWithSubmenu( |
| std::unique_ptr<QuickInsertItemWithSubmenuView> item_with_submenu) { |
| QuickInsertItemWithSubmenuView* item_ptr = |
| GetOrCreateListItemContainer()->AddItemWithSubmenu( |
| std::move(item_with_submenu)); |
| item_views_.push_back(item_ptr); |
| return item_ptr; |
| } |
| |
| QuickInsertItemView* QuickInsertSectionView::AddResult( |
| const QuickInsertSearchResult& result, |
| QuickInsertPreviewBubbleController* preview_controller, |
| LocalFileResultStyle local_file_result_style, |
| SelectResultCallback select_result_callback) { |
| auto item = CreateItemFromResult(result, preview_controller, asset_fetcher_, |
| section_width_, local_file_result_style, |
| std::move(select_result_callback)); |
| if (views::IsViewClass<QuickInsertListItemView>(item.get())) { |
| return AddListItem(std::unique_ptr<QuickInsertListItemView>( |
| views::AsViewClass<QuickInsertListItemView>(item.release()))); |
| } |
| if (views::IsViewClass<QuickInsertImageItemView>(item.get())) { |
| std::unique_ptr<QuickInsertImageItemView> image_item( |
| views::AsViewClass<QuickInsertImageItemView>(item.release())); |
| if (local_file_result_style == LocalFileResultStyle::kRow) { |
| return AddImageRowItem(std::move(image_item)); |
| } else { |
| return AddImageGridItem(std::move(image_item)); |
| } |
| } |
| if (views::IsViewClass<QuickInsertItemWithSubmenuView>(item.get())) { |
| return AddItemWithSubmenu(std::unique_ptr<QuickInsertItemWithSubmenuView>( |
| views::AsViewClass<QuickInsertItemWithSubmenuView>(item.release()))); |
| } |
| NOTREACHED(); |
| } |
| |
| void QuickInsertSectionView::ClearItems() { |
| item_containers_.clear(); |
| item_views_.clear(); |
| if (image_item_grid_ != nullptr) { |
| RemoveChildViewT(image_item_grid_.ExtractAsDangling()); |
| } |
| if (list_item_container_ != nullptr) { |
| RemoveChildViewT(list_item_container_.ExtractAsDangling()); |
| } |
| } |
| |
| views::View* QuickInsertSectionView::GetTopItem() { |
| return item_containers_.empty() ? nullptr |
| : item_containers_.front()->GetTopItem(); |
| } |
| |
| views::View* QuickInsertSectionView::GetBottomItem() { |
| return item_containers_.empty() ? nullptr |
| : item_containers_.back()->GetBottomItem(); |
| } |
| |
| views::View* QuickInsertSectionView::GetItemAbove(views::View* item) { |
| auto it = FindContainerForItem(item_containers_, item); |
| if (it == item_containers_.end()) { |
| return nullptr; |
| } |
| |
| if (views::View* result = (*it)->GetItemAbove(item)) { |
| return result; |
| } |
| |
| // Get the bottom item of the above container. |
| return it == item_containers_.begin() ? nullptr |
| : (*std::prev(it))->GetBottomItem(); |
| } |
| |
| views::View* QuickInsertSectionView::GetItemBelow(views::View* item) { |
| auto it = FindContainerForItem(item_containers_, item); |
| if (it == item_containers_.end()) { |
| return nullptr; |
| } |
| |
| if (views::View* result = (*it)->GetItemBelow(item)) { |
| return result; |
| } |
| |
| // Get the top item of the below container. |
| return it == item_containers_.end() - 1 ? nullptr |
| : (*std::next(it))->GetTopItem(); |
| } |
| |
| views::View* QuickInsertSectionView::GetItemLeftOf(views::View* item) { |
| auto it = FindContainerForItem(item_containers_, item); |
| return it == item_containers_.end() ? nullptr : (*it)->GetItemLeftOf(item); |
| } |
| |
| views::View* QuickInsertSectionView::GetItemRightOf(views::View* item) { |
| auto it = FindContainerForItem(item_containers_, item); |
| return it == item_containers_.end() ? nullptr : (*it)->GetItemRightOf(item); |
| } |
| |
| void QuickInsertSectionView::SetImageRowProperties( |
| std::u16string accessible_name, |
| base::RepeatingClosure more_items_button_callback, |
| std::u16string more_items_button_accessible_name) { |
| image_row_properties_.accessible_name = std::move(accessible_name); |
| image_row_properties_.more_items_button_callback = |
| std::move(more_items_button_callback); |
| image_row_properties_.more_items_button_accessible_name = |
| std::move(more_items_button_accessible_name); |
| } |
| |
| views::View* QuickInsertSectionView::GetImageRowMoreItemsButtonForTesting() { |
| return image_item_row_ == nullptr |
| ? nullptr |
| : image_item_row_->GetMoreItemsButtonForTesting(); // IN-TEST |
| } |
| |
| QuickInsertSectionView::ImageRowProperties::ImageRowProperties() = default; |
| |
| QuickInsertSectionView::ImageRowProperties::~ImageRowProperties() = default; |
| |
| QuickInsertListItemContainerView* |
| QuickInsertSectionView::GetOrCreateListItemContainer() { |
| if (list_item_container_ == nullptr) { |
| list_item_container_ = |
| AddChildView(std::make_unique<QuickInsertListItemContainerView>()); |
| item_containers_.push_back(list_item_container_); |
| } |
| return list_item_container_; |
| } |
| |
| QuickInsertImageItemGridView* |
| QuickInsertSectionView::GetOrCreateImageItemGrid() { |
| if (image_item_grid_ == nullptr) { |
| image_item_grid_ = |
| AddChildView(std::make_unique<QuickInsertImageItemGridView>( |
| section_width_, |
| /*has_top_margin=*/title_container_->children().empty())); |
| item_containers_.push_back(image_item_grid_); |
| } |
| return image_item_grid_; |
| } |
| |
| QuickInsertImageItemRowView* QuickInsertSectionView::GetOrCreateImageItemRow() { |
| if (image_item_row_ == nullptr) { |
| image_item_row_ = |
| AddChildView(std::make_unique<QuickInsertImageItemRowView>( |
| image_row_properties_.more_items_button_callback, |
| image_row_properties_.more_items_button_accessible_name)); |
| image_item_row_->SetLeadingIcon(ui::ImageModel::FromVectorIcon( |
| kFilesAppIcon, cros_tokens::kCrosSysOnSurface, kIconSize)); |
| image_item_row_->GetViewAccessibility().SetName( |
| image_row_properties_.accessible_name); |
| item_containers_.push_back(image_item_row_); |
| } |
| return image_item_row_; |
| } |
| |
| BEGIN_METADATA(QuickInsertSectionView) |
| END_METADATA |
| |
| } // namespace ash |