blob: c61307b19e6029ed5dbf057ef812fdbe214fe0be [file] [log] [blame]
// 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 "chrome/browser/ui/ash/picker/picker_file_suggester.h"
#include "base/barrier_callback.h"
#include "base/time/time.h"
#include "chrome/browser/ash/app_list/search/files/file_title.h"
#include "chrome/browser/ash/drive/drive_integration_service.h"
#include "chrome/browser/ash/fileapi/recent_file.h"
#include "chrome/browser/ash/fileapi/recent_model.h"
#include "chrome/browser/ash/fileapi/recent_model_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/storage_partition.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_url.h"
#include "storage/common/file_system/file_system_types.h"
namespace {
using LocalFile = PickerFileSuggester::LocalFile;
using DriveFile = PickerFileSuggester::DriveFile;
constexpr base::TimeDelta kMaxFileRecencyDelta = base::Days(30);
storage::FileSystemContext* GetFileSystemContextForProfile(Profile* profile) {
content::StoragePartition* storage = profile->GetDefaultStoragePartition();
return storage->GetFileSystemContext();
}
void GetRecentFiles(Profile* profile,
ash::RecentModel::GetRecentFilesCallback callback) {
const scoped_refptr<storage::FileSystemContext> file_system_context =
GetFileSystemContextForProfile(profile);
if (!file_system_context) {
return;
}
ash::RecentModel* model = ash::RecentModelFactory::GetForProfile(profile);
if (!model) {
return;
}
model->GetRecentFiles(file_system_context.get(), GURL(), /*query=*/"",
kMaxFileRecencyDelta, ash::RecentModel::FileType::kAll,
/*invalidate_cache=*/false, std::move(callback));
}
void GetDriveFileMetadata(
drive::DriveIntegrationService* drive_integration,
const ash::RecentFile& file,
base::OnceCallback<void(std::optional<DriveFile>)> callback) {
const storage::FileSystemURL& url = file.url();
if (url.type() != storage::kFileSystemTypeDriveFs) {
std::move(callback).Run(std::nullopt);
return;
}
const base::FilePath& path = url.path();
drive_integration->GetMetadata(
path, base::BindOnce(
[](const base::FilePath& path, drive::FileError error,
drivefs::mojom::FileMetadataPtr metadata)
-> std::optional<DriveFile> {
if (error != drive::FILE_ERROR_OK) {
return std::nullopt;
}
return DriveFile{.title = app_list::GetFileTitle(path),
.url = GURL(metadata->alternate_url)};
},
path)
.Then(std::move(callback)));
}
std::vector<DriveFile> FilterDriveFiles(
std::vector<std::optional<DriveFile>> files) {
std::vector<DriveFile> filtered;
filtered.reserve(files.size());
for (std::optional<DriveFile>& file : files) {
if (file.has_value()) {
filtered.push_back(std::move(*file));
}
}
filtered.shrink_to_fit();
return filtered;
}
} // namespace
PickerFileSuggester::PickerFileSuggester(Profile* profile)
: profile_(profile) {}
PickerFileSuggester::~PickerFileSuggester() = default;
void PickerFileSuggester::GetRecentLocalFiles(
RecentLocalFilesCallback callback) {
GetRecentFiles(
profile_,
base::BindOnce(&PickerFileSuggester::OnGetRecentLocalFiles,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void PickerFileSuggester::GetRecentDriveFiles(
RecentDriveFilesCallback callback) {
GetRecentFiles(
profile_,
base::BindOnce(&PickerFileSuggester::OnGetRecentDriveFiles,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void PickerFileSuggester::OnGetRecentLocalFiles(
RecentLocalFilesCallback callback,
const std::vector<ash::RecentFile>& recent_files) {
std::vector<LocalFile> files;
files.reserve(recent_files.size());
for (const ash::RecentFile& recent_file : recent_files) {
const storage::FileSystemURL& url = recent_file.url();
if (url.type() == storage::kFileSystemTypeLocal) {
const base::FilePath& path = url.path();
files.push_back({.title = app_list::GetFileTitle(path), .path = path});
}
}
std::move(callback).Run(std::move(files));
}
void PickerFileSuggester::OnGetRecentDriveFiles(
RecentDriveFilesCallback callback,
const std::vector<ash::RecentFile>& recent_files) {
drive::DriveIntegrationService* drive_integration =
drive::DriveIntegrationServiceFactory::FindForProfile(profile_);
if (!drive_integration) {
std::move(callback).Run({});
}
auto barrier_callback = base::BarrierCallback<std::optional<DriveFile>>(
/*num_callbacks=*/recent_files.size(),
/*done_callback=*/base::BindOnce(FilterDriveFiles)
.Then(std::move(callback)));
for (const ash::RecentFile& recent_file : recent_files) {
GetDriveFileMetadata(drive_integration, recent_file, barrier_callback);
}
}