chromium/ash/picker/picker_suggestions_controller.cc

// 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/picker/picker_suggestions_controller.h"

#include "ash/picker/model/picker_mode_type.h"
#include "ash/picker/model/picker_model.h"
#include "ash/picker/picker_clipboard_history_provider.h"
#include "ash/picker/picker_shortcuts.h"
#include "ash/picker/search/picker_date_search.h"
#include "ash/picker/search/picker_math_search.h"
#include "ash/public/cpp/picker/picker_category.h"
#include "ash/public/cpp/picker/picker_client.h"
#include "ash/public/cpp/picker/picker_search_result.h"

namespace ash {
namespace {

constexpr int kMaxRecentFiles = 10;
constexpr int kMaxRecentLinks = 10;
}

PickerSuggestionsController::PickerSuggestionsController(PickerClient* client)
    : client_(client) {}

PickerSuggestionsController::~PickerSuggestionsController() = default;

std::vector<PickerSearchResult> GetMostRecentResult(
    std::vector<PickerSearchResult> results) {
  if (results.empty()) {
    return {};
  }
  return {results[0]};
}

void PickerSuggestionsController::GetSuggestions(const PickerModel& model,
                                                 SuggestionsCallback callback) {
  if (model.GetMode() == PickerModeType::kUnfocused) {
    std::vector<PickerSearchResult> new_window_results;
    for (PickerNewWindowResult::Type type : {
             PickerNewWindowResult::Type::kDoc,
             PickerNewWindowResult::Type::kSheet,
             PickerNewWindowResult::Type::kSlide,
             PickerNewWindowResult::Type::kChrome,
         }) {
      new_window_results.push_back(PickerNewWindowResult(type));
    }
    callback.Run(std::move(new_window_results));
  }

  if (model.GetMode() == PickerModeType::kUnfocused ||
      model.GetMode() == PickerModeType::kNoSelection) {
    callback.Run({PickerCapsLockResult(!model.is_caps_lock_enabled(),
                                       GetPickerShortcutForCapsLock())});
  }

  if (base::Contains(model.GetAvailableCategories(),
                     PickerCategory::kEditorRewrite)) {
    client_->GetSuggestedEditorResults(callback);
  }

  if (model.GetMode() == PickerModeType::kHasSelection) {
    std::vector<PickerSearchResult> case_transform_results;
    for (PickerCaseTransformResult::Type type : {
             PickerCaseTransformResult::Type::kUpperCase,
             PickerCaseTransformResult::Type::kLowerCase,
             PickerCaseTransformResult::Type::kTitleCase,
         }) {
      case_transform_results.push_back(PickerCaseTransformResult(type));
    }
    callback.Run(std::move(case_transform_results));
  }

  // TODO: b/344685737 - Rank and collect suggestions in a more intelligent way.
  for (PickerCategory category : model.GetRecentResultsCategories()) {
    // Special case certain categories where we can save computation by only
    // asking for 1 result.
    // TODO: b/357740941: Request only one Drive file once directory filtering
    // is implemented inside DriveFS.
    switch (category) {
      case PickerCategory::kLinks:
        client_->GetSuggestedLinkResults(
            /*max_results=*/1,
            base::BindRepeating(&GetMostRecentResult).Then(callback));
        break;
      case PickerCategory::kLocalFiles:
        client_->GetRecentLocalFileResults(
            /*max_results=*/1,
            base::BindRepeating(&GetMostRecentResult).Then(callback));
        break;
      case PickerCategory::kDriveFiles:
        client_->GetRecentDriveFileResults(
            /*max_results=*/5,
            base::BindRepeating(&GetMostRecentResult).Then(callback));
        break;
      default:
        GetSuggestionsForCategory(
            category, base::BindRepeating(&GetMostRecentResult).Then(callback));
        break;
    }
  }
}

void PickerSuggestionsController::GetSuggestionsForCategory(
    PickerCategory category,
    SuggestionsCallback callback) {
  switch (category) {
    case PickerCategory::kEditorWrite:
    case PickerCategory::kEditorRewrite:
      NOTREACHED_NORETURN();
    case PickerCategory::kLinks:
      client_->GetSuggestedLinkResults(kMaxRecentLinks, std::move(callback));
      return;
    case PickerCategory::kEmojisGifs:
    case PickerCategory::kEmojis:
      NOTREACHED_NORETURN();
    case PickerCategory::kDriveFiles:
      client_->GetRecentDriveFileResults(kMaxRecentFiles, std::move(callback));
      return;
    case PickerCategory::kLocalFiles:
      client_->GetRecentLocalFileResults(kMaxRecentFiles, std::move(callback));
      return;
    case PickerCategory::kDatesTimes:
      std::move(callback).Run(PickerSuggestedDateResults());
      break;
    case PickerCategory::kUnitsMaths:
      std::move(callback).Run(PickerMathExamples());
      break;
    case PickerCategory::kClipboard:
      clipboard_provider_.FetchResults(std::move(callback));
      return;
  }
}

}  // namespace ash