blob: 0daad9a470d7d4d68421c0a46498c90c6be842e5 [file] [log] [blame]
// Copyright 2023 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/birch/birch_model.h"
#include <memory>
#include <vector>
#include "ash/birch/birch_item.h"
#include "ash/birch/birch_weather_provider.h"
#include "ash/constants/ash_features.h"
#include "ash/shell.h"
#include "base/functional/callback_forward.h"
#include "base/time/time.h"
namespace ash {
namespace {
constexpr int kDataFetchTimeoutInMs = 1000;
} // namespace
BirchModel::PendingRequest::PendingRequest() = default;
BirchModel::PendingRequest::~PendingRequest() = default;
BirchModel::BirchModel() {
if (features::IsBirchWeatherEnabled()) {
weather_provider_ = std::make_unique<BirchWeatherProvider>(this);
}
}
BirchModel::~BirchModel() = default;
void BirchModel::SetCalendarItems(
std::vector<BirchCalendarItem> calendar_items) {
if (calendar_items != calendar_items_) {
calendar_items_ = std::move(calendar_items);
}
is_calendar_data_fresh_ = true;
MaybeRespondToDataFetchRequest();
}
void BirchModel::SetFileSuggestItems(
std::vector<BirchFileItem> file_suggest_items) {
if (file_suggest_items_ != file_suggest_items) {
file_suggest_items_ = std::move(file_suggest_items);
}
is_files_data_fresh_ = true;
MaybeRespondToDataFetchRequest();
}
void BirchModel::SetRecentTabItems(std::vector<BirchTabItem> recent_tab_items) {
if (recent_tab_items_ != recent_tab_items) {
recent_tab_items_ = std::move(recent_tab_items);
}
is_tabs_data_fresh_ = true;
MaybeRespondToDataFetchRequest();
}
void BirchModel::SetWeatherItems(std::vector<BirchWeatherItem> weather_items) {
if (weather_items_ != weather_items) {
weather_items_ = std::move(weather_items);
}
is_weather_data_fresh_ = true;
MaybeRespondToDataFetchRequest();
}
void BirchModel::RequestBirchDataFetch(base::OnceClosure callback) {
const bool fetch_in_progress = !pending_requests_.empty();
size_t request_id = next_request_id_++;
PendingRequest& request = pending_requests_[request_id];
request.callback = std::move(callback);
request.timer = std::make_unique<base::OneShotTimer>();
request.timer->Start(FROM_HERE, base::Milliseconds(kDataFetchTimeoutInMs),
base::BindOnce(&BirchModel::HandleRequestTimeout,
base::Unretained(this), request_id));
if (fetch_in_progress) {
return;
}
is_calendar_data_fresh_ = false;
is_files_data_fresh_ = false;
is_tabs_data_fresh_ = false;
is_weather_data_fresh_ = false;
// TODO(b/305094143): Call this before we begin showing birch views.
if (birch_client_) {
birch_client_->RequestBirchDataFetch();
}
if (weather_provider_) {
weather_provider_->RequestBirchDataFetch();
}
}
std::vector<std::unique_ptr<BirchItem>> BirchModel::GetAllItems() const {
std::vector<std::unique_ptr<BirchItem>> all_items;
// TODO(b/305094126): Sort items by priority.
for (auto& event : calendar_items_) {
all_items.push_back(std::make_unique<BirchCalendarItem>(event));
}
for (auto& tab : recent_tab_items_) {
all_items.push_back(std::make_unique<BirchTabItem>(tab));
}
for (auto& file_suggestion : file_suggest_items_) {
all_items.push_back(std::make_unique<BirchFileItem>(file_suggestion));
}
for (auto& weather_item : weather_items_) {
all_items.push_back(std::make_unique<BirchWeatherItem>(weather_item));
}
return all_items;
}
bool BirchModel::IsDataFresh() {
// TODO(jamescook): Include calendar freshness.
return (!birch_client_ || (is_files_data_fresh_ && is_tabs_data_fresh_)) &&
(!weather_provider_ || is_weather_data_fresh_);
}
void BirchModel::OverrideWeatherProviderForTest(
std::unique_ptr<BirchClient> weather_provider) {
CHECK(weather_provider_);
weather_provider_ = std::move(weather_provider);
}
void BirchModel::HandleRequestTimeout(size_t request_id) {
auto request = pending_requests_.find(request_id);
if (request == pending_requests_.end()) {
return;
}
base::OnceClosure callback = std::move(request->second.callback);
pending_requests_.erase(request);
std::move(callback).Run();
}
void BirchModel::MaybeRespondToDataFetchRequest() {
if (!IsDataFresh()) {
return;
}
std::vector<base::OnceClosure> callbacks;
for (auto& request : pending_requests_) {
callbacks.push_back(std::move(request.second.callback));
}
pending_requests_.clear();
for (auto& callback : callbacks) {
std::move(callback).Run();
}
}
} // namespace ash