910e62b5创建于 1月15日历史提交
// 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/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