diff --git a/ash/picker/model/picker_model.cc b/ash/picker/model/picker_model.cc index 6ff429a756b8a..6ed175bf149ac 100644 --- a/ash/picker/model/picker_model.cc +++ b/ash/picker/model/picker_model.cc @@ -67,6 +67,18 @@ std::vector<PickerCategory> PickerModel::GetAvailableCategories() const { return categories; } +std::vector<PickerCategory> PickerModel::GetRecentResultsCategories() const { + if (HasSelectedText()) { + return std::vector<PickerCategory>{}; + } + + return { + PickerCategory::kDriveFiles, + PickerCategory::kLocalFiles, + PickerCategory::kLinks, + }; +} + bool PickerModel::HasSelectedText() const { return !selected_text_.empty(); } diff --git a/ash/picker/model/picker_model.h b/ash/picker/model/picker_model.h index 33847b49be239..423a09b5eec43 100644 --- a/ash/picker/model/picker_model.h +++ b/ash/picker/model/picker_model.h @@ -33,6 +33,8 @@ class ASH_EXPORT PickerModel { std::vector<PickerCategory> GetAvailableCategories() const; + std::vector<PickerCategory> GetRecentResultsCategories() const; + std::u16string_view selected_text() const; bool HasSelectedText() const; diff --git a/ash/picker/picker_controller.cc b/ash/picker/picker_controller.cc index 33f3e740449bb..e3a1ce0c35eee 100644 --- a/ash/picker/picker_controller.cc +++ b/ash/picker/picker_controller.cc @@ -361,8 +361,9 @@ std::vector<PickerCategory> PickerController::GetAvailableCategories() { : model_->GetAvailableCategories(); } -bool PickerController::ShouldShowRecentResults() { - return model_ && !model_->HasSelectedText(); +std::vector<PickerCategory> PickerController::GetRecentResultsCategories() { + return model_ == nullptr ? std::vector<PickerCategory>{} + : model_->GetRecentResultsCategories(); } void PickerController::GetResultsForCategory(PickerCategory category, diff --git a/ash/picker/picker_controller.h b/ash/picker/picker_controller.h index e811d92eaffb7..7c59c74cc4048 100644 --- a/ash/picker/picker_controller.h +++ b/ash/picker/picker_controller.h @@ -75,7 +75,7 @@ class ASH_EXPORT PickerController // PickerViewDelegate: std::vector<PickerCategory> GetAvailableCategories() override; - bool ShouldShowRecentResults() override; + std::vector<PickerCategory> GetRecentResultsCategories() override; void GetResultsForCategory(PickerCategory category, SearchResultsCallback callback) override; void TransformSelectedText(PickerCategory category) override; diff --git a/ash/picker/views/picker_view.cc b/ash/picker/views/picker_view.cc index fb166fecd61c6..a457616686b93 100644 --- a/ash/picker/views/picker_view.cc +++ b/ash/picker/views/picker_view.cc @@ -146,6 +146,19 @@ PickerCategory GetCategoryForMoreResults(PickerSectionType type) { } } +std::vector<PickerSearchResult> GetMostRecentResult( + std::vector<PickerSearchResultsSection> results) { + if (results.empty() || + results[0].type() != PickerSectionType::kRecentlyUsed) { + return {}; + } + base::span<const PickerSearchResult> search_results = results[0].results(); + if (search_results.empty()) { + return {}; + } + return {search_results[0]}; +} + } // namespace PickerView::PickerView(PickerViewDelegate* delegate, @@ -209,6 +222,13 @@ void PickerView::SelectZeroStateResult(const PickerSearchResult& result) { SelectSearchResult(result); } +void PickerView::GetZeroStateRecentResults(PickerCategory category, + SearchResultsCallback callback) { + delegate_->GetResultsForCategory( + category, + base::BindRepeating(&GetMostRecentResult).Then(std::move(callback))); +} + void PickerView::GetSuggestedZeroStateEditorResults( SuggestedEditorResultsCallback callback) { delegate_->GetSuggestedEditorResults(std::move(callback)); @@ -397,7 +417,7 @@ void PickerView::AddContentsViewWithSeparator(PickerLayoutType layout_type) { zero_state_view_ = contents_view_->AddPage(std::make_unique<PickerZeroStateView>( this, delegate_->GetAvailableCategories(), - delegate_->ShouldShowRecentResults(), kMaxSize.width(), + delegate_->GetRecentResultsCategories(), kMaxSize.width(), delegate_->GetAssetFetcher())); category_view_ = contents_view_->AddPage(std::make_unique<PickerCategoryView>( diff --git a/ash/picker/views/picker_view.h b/ash/picker/views/picker_view.h index bbc6ddf4fae7a..0e7f5f606b381 100644 --- a/ash/picker/views/picker_view.h +++ b/ash/picker/views/picker_view.h @@ -73,6 +73,8 @@ class ASH_EXPORT PickerView : public views::WidgetDelegateView, // PickerZeroStateViewDelegate: void SelectZeroStateCategory(PickerCategory category) override; void SelectZeroStateResult(const PickerSearchResult& result) override; + void GetZeroStateRecentResults(PickerCategory category, + SearchResultsCallback callback) override; void GetSuggestedZeroStateEditorResults( SuggestedEditorResultsCallback callback) override; void NotifyPseudoFocusChanged(views::View* view) override; diff --git a/ash/picker/views/picker_view_delegate.h b/ash/picker/views/picker_view_delegate.h index c269d38caef4e..429b470b7065a 100644 --- a/ash/picker/views/picker_view_delegate.h +++ b/ash/picker/views/picker_view_delegate.h @@ -32,8 +32,9 @@ class ASH_EXPORT PickerViewDelegate { virtual std::vector<PickerCategory> GetAvailableCategories() = 0; - // Returns whether we should show suggested results in zero state view. - virtual bool ShouldShowRecentResults() = 0; + // Returns categories for which we should show recent results in zero state + // view. + virtual std::vector<PickerCategory> GetRecentResultsCategories() = 0; // Gets initially suggested results for category. Results will be returned via // `callback`, which may be called multiples times to update the results. diff --git a/ash/picker/views/picker_view_unittest.cc b/ash/picker/views/picker_view_unittest.cc index 5847477808415..567402cb96417 100644 --- a/ash/picker/views/picker_view_unittest.cc +++ b/ash/picker/views/picker_view_unittest.cc @@ -115,7 +115,9 @@ class FakePickerViewDelegate : public PickerViewDelegate { requested_case_transformation_category_ = category; } - bool ShouldShowRecentResults() override { return true; } + std::vector<PickerCategory> GetRecentResultsCategories() override { + return {PickerCategory::kDriveFiles}; + } void GetResultsForCategory(PickerCategory category, SearchResultsCallback callback) override { diff --git a/ash/picker/views/picker_widget_unittest.cc b/ash/picker/views/picker_widget_unittest.cc index 3740cfd735939..53b245558350a 100644 --- a/ash/picker/views/picker_widget_unittest.cc +++ b/ash/picker/views/picker_widget_unittest.cc @@ -32,7 +32,9 @@ class FakePickerViewDelegate : public PickerViewDelegate { public: // PickerViewDelegate: std::vector<PickerCategory> GetAvailableCategories() override { return {}; } - bool ShouldShowRecentResults() override { return false; } + std::vector<PickerCategory> GetRecentResultsCategories() override { + return {}; + } void GetResultsForCategory(PickerCategory category, SearchResultsCallback callback) override {} void TransformSelectedText(PickerCategory category) override {} diff --git a/ash/picker/views/picker_zero_state_view.cc b/ash/picker/views/picker_zero_state_view.cc index 1ddc1b56d351f..a41682e691f06 100644 --- a/ash/picker/views/picker_zero_state_view.cc +++ b/ash/picker/views/picker_zero_state_view.cc @@ -48,54 +48,11 @@ #include "ui/views/view_utils.h" namespace ash { -namespace { -constexpr base::TimeDelta kClipboardRecency = base::Seconds(60); - -std::unique_ptr<PickerListItemView> CreateListItemViewForClipboardResult( - const PickerSearchResult::ClipboardData& data, - PickerListItemView::SelectItemCallback callback) { - auto item_view = std::make_unique<PickerListItemView>(std::move(callback)); - item_view->SetLeadingIcon(ui::ImageModel::FromVectorIcon( - kClipboardIcon, cros_tokens::kCrosSysOnSurface)); - item_view->SetSecondaryText( - l10n_util::GetStringUTF16(IDS_PICKER_FROM_CLIPBOARD_TEXT)); - switch (data.display_format) { - case PickerSearchResult::ClipboardData::DisplayFormat::kFile: - case PickerSearchResult::ClipboardData::DisplayFormat::kText: - item_view->SetPrimaryText(data.display_text); - break; - case PickerSearchResult::ClipboardData::DisplayFormat::kImage: - if (!data.display_image.has_value()) { - return nullptr; - } - item_view->SetPrimaryImage( - std::make_unique<views::ImageView>(*data.display_image)); - break; - case PickerSearchResult::ClipboardData::DisplayFormat::kHtml: - item_view->SetPrimaryText( - l10n_util::GetStringUTF16(IDS_PICKER_HTML_CONTENT)); - break; - } - return item_view; -} - -std::unique_ptr<PickerListItemView> CreateListItemViewForSearchResult( - const PickerSearchResult& result, - PickerListItemView::SelectItemCallback callback) { - // Only supports Clipboard results right now. - if (auto* data = - std::get_if<PickerSearchResult::ClipboardData>(&result.data())) { - return CreateListItemViewForClipboardResult(*data, std::move(callback)); - } - return nullptr; -} - -} // namespace PickerZeroStateView::PickerZeroStateView( PickerZeroStateViewDelegate* delegate, base::span<const PickerCategory> available_categories, - bool show_recent_results, + base::span<const PickerCategory> recent_results_categories, int picker_view_width, PickerAssetFetcher* asset_fetcher) : delegate_(delegate) { @@ -105,12 +62,11 @@ PickerZeroStateView::PickerZeroStateView( section_list_view_ = AddChildView(std::make_unique<PickerSectionListView>( picker_view_width, asset_fetcher)); - if (show_recent_results) { - clipboard_provider_ = std::make_unique<PickerClipboardProvider>(); - clipboard_provider_->FetchResults( + for (PickerCategory category : recent_results_categories) { + delegate_->GetZeroStateRecentResults( + category, base::BindRepeating(&PickerZeroStateView::OnFetchRecentResults, - weak_ptr_factory_.GetWeakPtr()), - u"", kClipboardRecency); + weak_ptr_factory_.GetWeakPtr())); } if (base::Contains(available_categories, PickerCategory::kEditorRewrite)) { @@ -324,13 +280,9 @@ void PickerZeroStateView::OnFetchRecentResults( GetSectionTitleForPickerSectionType(PickerSectionType::kRecentlyUsed)); } for (const auto& result : results) { - if (std::unique_ptr<PickerListItemView> item_view = - CreateListItemViewForSearchResult( - result, - base::BindRepeating(&PickerZeroStateView::OnResultSelected, - weak_ptr_factory_.GetWeakPtr(), result))) { - recent_section_view_->AddListItem(std::move(item_view)); - } + recent_section_view_->AddResult( + result, base::BindRepeating(&PickerZeroStateView::OnResultSelected, + weak_ptr_factory_.GetWeakPtr(), result)); } SetPseudoFocusedView(section_list_view_->GetTopItem()); } diff --git a/ash/picker/views/picker_zero_state_view.h b/ash/picker/views/picker_zero_state_view.h index 2fa876a61044f..a4e0db0450131 100644 --- a/ash/picker/views/picker_zero_state_view.h +++ b/ash/picker/views/picker_zero_state_view.h @@ -39,7 +39,7 @@ class ASH_EXPORT PickerZeroStateView : public PickerPageView { explicit PickerZeroStateView( PickerZeroStateViewDelegate* delegate, base::span<const PickerCategory> available_categories, - bool show_suggested_results, + base::span<const PickerCategory> recent_results_categories, int picker_view_width, PickerAssetFetcher* asset_fetcher); PickerZeroStateView(const PickerZeroStateView&) = delete; diff --git a/ash/picker/views/picker_zero_state_view_delegate.h b/ash/picker/views/picker_zero_state_view_delegate.h index 134e76606ac95..00fee1b334318 100644 --- a/ash/picker/views/picker_zero_state_view_delegate.h +++ b/ash/picker/views/picker_zero_state_view_delegate.h @@ -22,10 +22,16 @@ class ASH_EXPORT PickerZeroStateViewDelegate { using SuggestedEditorResultsCallback = base::OnceCallback<void(std::vector<PickerSearchResult>)>; + using SearchResultsCallback = + base::RepeatingCallback<void(std::vector<PickerSearchResult>)>; + virtual void SelectZeroStateCategory(PickerCategory category) = 0; virtual void SelectZeroStateResult(const PickerSearchResult& result) = 0; + virtual void GetZeroStateRecentResults(PickerCategory category, + SearchResultsCallback callback) = 0; + virtual void GetSuggestedZeroStateEditorResults( SuggestedEditorResultsCallback callback) = 0; diff --git a/ash/picker/views/picker_zero_state_view_unittest.cc b/ash/picker/views/picker_zero_state_view_unittest.cc index 28f552ec271d1..58fbcb90c5372 100644 --- a/ash/picker/views/picker_zero_state_view_unittest.cc +++ b/ash/picker/views/picker_zero_state_view_unittest.cc @@ -34,6 +34,7 @@ namespace ash { namespace { +using ::testing::_; using ::testing::AllOf; using ::testing::Contains; using ::testing::ElementsAre; @@ -79,6 +80,10 @@ class MockZeroStateViewDelegate : public PickerZeroStateViewDelegate { GetSuggestedZeroStateEditorResults, (SuggestedEditorResultsCallback), (override)); + MOCK_METHOD(void, + GetZeroStateRecentResults, + (PickerCategory, SearchResultsCallback), + (override)); MOCK_METHOD(void, NotifyPseudoFocusChanged, (views::View*), (override)); }; @@ -92,7 +97,7 @@ class PickerZeroStateViewTest : public views::ViewsTestBase { TEST_F(PickerZeroStateViewTest, CreatesCategorySections) { MockZeroStateViewDelegate mock_delegate; - PickerZeroStateView view(&mock_delegate, kAllCategories, true, kPickerWidth, + PickerZeroStateView view(&mock_delegate, kAllCategories, {}, kPickerWidth, &asset_fetcher_); EXPECT_THAT(view.section_views_for_testing(), @@ -109,7 +114,7 @@ TEST_F(PickerZeroStateViewTest, LeftClickSelectsCategory) { MockZeroStateViewDelegate mock_delegate; auto* view = widget->SetContentsView(std::make_unique<PickerZeroStateView>( &mock_delegate, std::vector<PickerCategory>{PickerCategory::kExpressions}, - false, kPickerWidth, &asset_fetcher_)); + std::vector<PickerCategory>{}, kPickerWidth, &asset_fetcher_)); widget->Show(); ASSERT_THAT(view->section_views_for_testing(), Contains(Key(PickerCategoryType::kGeneral))); @@ -129,43 +134,33 @@ TEST_F(PickerZeroStateViewTest, LeftClickSelectsCategory) { LeftClickOn(*category_view); } -TEST_F(PickerZeroStateViewTest, ShowsClipboardItems) { - base::UnguessableToken item_id; - testing::StrictMock<MockClipboardHistoryController> mock_clipboard; - EXPECT_CALL(mock_clipboard, GetHistoryValues) - .WillOnce( - [&item_id]( - ClipboardHistoryController::GetHistoryValuesCallback callback) { - ClipboardHistoryItemBuilder builder; - ClipboardHistoryItem item = - builder.SetFormat(ui::ClipboardInternalFormat::kText) - .SetText("test") - .Build(); - item_id = item.id(); - std::move(callback).Run({std::move(item)}); - }); +TEST_F(PickerZeroStateViewTest, ShowsRecentItems) { + MockZeroStateViewDelegate mock_delegate; + EXPECT_CALL(mock_delegate, + GetZeroStateRecentResults(PickerCategory::kDriveFiles, _)) + .WillOnce([](PickerCategory category, + MockZeroStateViewDelegate::SearchResultsCallback callback) { + std::move(callback).Run({PickerSearchResult::DriveFile( + /*title=*/u"test drive file", + /*url=*/GURL(), + /*icon=*/{})}); + }); std::unique_ptr<views::Widget> widget = CreateTestWidget(); widget->SetFullscreen(true); base::test::TestFuture<const PickerSearchResult&> future; - MockZeroStateViewDelegate mock_delegate; auto* view = widget->SetContentsView(std::make_unique<PickerZeroStateView>( - &mock_delegate, kAllCategories, true, kPickerWidth, &asset_fetcher_)); + &mock_delegate, kAllCategories, + std::vector<PickerCategory>{PickerCategory::kDriveFiles}, kPickerWidth, + &asset_fetcher_)); widget->Show(); - EXPECT_CALL( - mock_delegate, - SelectZeroStateResult(Property( - "data", &ash::PickerSearchResult::data, - VariantWith<ash::PickerSearchResult::ClipboardData>(AllOf( - Field("item_id", &ash::PickerSearchResult::ClipboardData::item_id, - item_id), - Field("display_format", - &ash::PickerSearchResult::ClipboardData::display_format, - PickerSearchResult::ClipboardData::DisplayFormat::kText), - Field("display_text", - &ash::PickerSearchResult::ClipboardData::display_text, - u"test")))))) + EXPECT_CALL(mock_delegate, + SelectZeroStateResult(Property( + "data", &ash::PickerSearchResult::data, + VariantWith<ash::PickerSearchResult::DriveFileData>(Field( + "title", &ash::PickerSearchResult::DriveFileData::title, + u"test drive file"))))) .Times(1); ASSERT_THAT(view->RecentSectionForTesting(), Not(IsNull())); @@ -175,35 +170,6 @@ TEST_F(PickerZeroStateViewTest, ShowsClipboardItems) { LeftClickOn(*item_view); } -TEST_F(PickerZeroStateViewTest, HidesRecentSectionWhenNoItemsToDisplay) { - testing::StrictMock<MockClipboardHistoryController> mock_clipboard; - EXPECT_CALL(mock_clipboard, GetHistoryValues) - .WillOnce( - [](ClipboardHistoryController::GetHistoryValuesCallback callback) { - std::move(callback).Run({}); - }); - - std::unique_ptr<views::Widget> widget = CreateTestWidget(); - widget->SetFullscreen(true); - MockZeroStateViewDelegate mock_delegate; - auto* view = widget->SetContentsView(std::make_unique<PickerZeroStateView>( - &mock_delegate, kAllCategories, true, kPickerWidth, &asset_fetcher_)); - widget->Show(); - - EXPECT_THAT(view->RecentSectionForTesting(), IsNull()); -} - -TEST_F(PickerZeroStateViewTest, DoesntShowClipboardItems) { - std::unique_ptr<views::Widget> widget = CreateTestWidget(); - widget->SetFullscreen(true); - MockZeroStateViewDelegate mock_delegate; - auto* view = widget->SetContentsView(std::make_unique<PickerZeroStateView>( - &mock_delegate, kAllCategories, false, kPickerWidth, &asset_fetcher_)); - widget->Show(); - - EXPECT_THAT(view->RecentSectionForTesting(), IsNull()); -} - TEST_F(PickerZeroStateViewTest, DoesntShowEditorRewriteCategoryForEmptySuggestions) { MockZeroStateViewDelegate mock_delegate; @@ -211,7 +177,7 @@ TEST_F(PickerZeroStateViewTest, .WillOnce([](MockZeroStateViewDelegate::SuggestedEditorResultsCallback callback) { std::move(callback).Run({}); }); PickerZeroStateView view(&mock_delegate, {{PickerCategory::kEditorRewrite}}, - false, kPickerWidth, &asset_fetcher_); + {}, kPickerWidth, &asset_fetcher_); EXPECT_THAT( view.section_views_for_testing(), @@ -239,7 +205,7 @@ TEST_F(PickerZeroStateViewTest, ShowsEditorSuggestionsAsItems) { }); }); PickerZeroStateView view(&mock_delegate, {{PickerCategory::kEditorRewrite}}, - false, kPickerWidth, &asset_fetcher_); + {}, kPickerWidth, &asset_fetcher_); EXPECT_THAT( view.section_views_for_testing(),