// 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.
#ifndef ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_TASKS_PROVIDER_H_
#define ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_TASKS_PROVIDER_H_
#include <compare>
#include <string>
#include <vector>
#include "ash/ash_export.h"
#include "ash/system/focus_mode/focus_mode_retry_util.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/time/time.h"
#include "google_apis/common/api_error_codes.h"
#include "ui/base/models/list_model.h"
namespace ash {
namespace api {
struct Task;
}
class TaskFetcher;
// Encapsulate information required to uniquely identify a task. Tasks are
// expected to be referenced within a list. However, we treat tasks as a flat
// collection so the list id needs to be retained.
struct TaskId {
bool empty() const { return !pending && (id.empty() || list_id.empty()); }
std::strong_ordering operator<=>(const TaskId& other) const;
bool operator==(const TaskId& other) const = default;
bool operator<(const TaskId& other) const = default;
std::string list_id;
std::string id;
// If true, the task is waiting to be sent to the server and does not have a
// valid `list_id` or `id`.
bool pending = false;
};
// Represents a task.
struct ASH_EXPORT FocusModeTask {
FocusModeTask();
~FocusModeTask();
FocusModeTask(const FocusModeTask&);
FocusModeTask(FocusModeTask&&);
FocusModeTask& operator=(const FocusModeTask&);
FocusModeTask& operator=(FocusModeTask&&);
// TODO: Replace the condition below with `FocusModeTask::IsValid()`.
bool empty() const { return task_id.empty(); }
TaskId task_id;
std::string title;
bool completed;
// The time when this task was last updated.
base::Time updated;
// Optional due time for the task.
std::optional<base::Time> due;
};
// A specialized interface that Focus Mode can use to fetch a filtered list of
// tasks to display.
class ASH_EXPORT FocusModeTasksProvider {
public:
// Done callback for `AddTask` and `UpdateTaskTitle`. If the request completes
// successfully, `task_entry` points to the newly created or updated
// `FocusModeTask`, or an empty `FocusModeTask` with nullptr members
// otherwise.
using OnTaskSavedCallback =
base::OnceCallback<void(const FocusModeTask& task_entry)>;
using OnGetTasksCallback =
base::OnceCallback<void(const std::vector<FocusModeTask>& tasks)>;
using OnGetTaskCallback =
base::OnceCallback<void(const FocusModeTask& task_entry)>;
FocusModeTasksProvider();
FocusModeTasksProvider(const FocusModeTasksProvider&) = delete;
FocusModeTasksProvider& operator=(const FocusModeTasksProvider&) = delete;
~FocusModeTasksProvider();
// Provides a sorted list of `FocusModeTask` instances that can be displayed
// in Focus Mode. The provided `callback` is invoked asynchronously when tasks
// have been fetched.
void GetSortedTaskList(OnGetTasksCallback callback);
// Gets an individual task from the `task_list_id` with `task_id`. Since
// completed tasks will not be returned by the delegate, we will update the
// `completed` field to signifiy if the task has been completed or not.
// Returns a `FocusModeTask` in `callback`, or an empty `FocusModeTask` if an
// error has occurred.
void GetTask(const std::string& task_list_id,
const std::string& task_id,
OnGetTaskCallback callback);
// Creates a new task with name `title` and adds it to `task_list_`. Returns
// the added `FocusModeTask` in `callback`, or an empty `FocusModeTask` if an
// error has occurred. Note that this will clear the internal cache.
void AddTask(const std::string& title, OnTaskSavedCallback callback);
// Finds the task by `task_list_id` and `task_id` and updates the task title
// and completion status. Returns a `FocusModeTask` in `callback`, or an empty
// `FocusModeTask` if the task could not be found or an error has occurred.
void UpdateTask(const std::string& task_list_id,
const std::string& task_id,
const std::string& title,
bool completed,
OnTaskSavedCallback callback);
// This kicks off a fetch of tasks from the backend.
void ScheduleTaskListUpdate();
// Clears all the cached tasks data.
void Reset();
const std::vector<FocusModeTask> TasksForTesting() const;
private:
void OnTasksFetched();
void OnTasksFetchedForTask(
const std::string& task_list_id,
const std::string& task_id,
OnGetTaskCallback callback,
bool success,
std::optional<google_apis::ApiErrorCode> http_error,
const ui::ListModel<api::Task>* api_tasks);
void OnTaskAdded(const std::string& title,
OnTaskSavedCallback callback,
google_apis::ApiErrorCode http_error,
const api::Task* api_task);
void OnTaskUpdated(const std::string& task_list_id,
const std::string& task_id,
const std::string& title,
bool completed,
OnTaskSavedCallback callback,
google_apis::ApiErrorCode http_error,
const api::Task* api_task);
// Requests the server to add the new task.
void AddTaskInternal(const std::string& title, OnTaskSavedCallback callback);
// Requests the server to update the existing task.
void UpdateTaskInternal(const std::string& task_list_id,
const std::string& task_id,
const std::string& title,
bool completed,
OnTaskSavedCallback callback);
// Called only after the add or update request is successful.
void UpdateOrInsertTask(const std::string& task_list_id,
const api::Task* api_task,
OnTaskSavedCallback callback);
// Returns cached tasks according to this sort order:
// 1. Entries added/updated by the user during the lifetime of this provider.
// 2. Entries containing `Task`s which are past due.
// 3. Entries containing `Task`s which are due in the next 24 hours.
// 4. All other entries.
// Entries within each group are sorted by their `Task`'s update date.
std::vector<FocusModeTask> GetSortedTasksImpl();
// Cache of tasks retrieved from the API.
std::vector<FocusModeTask> tasks_;
// Pending UI requests to get all tasks.
std::vector<OnGetTasksCallback> get_tasks_requests_;
// The ID of the task list to use when creating new tasks. This will be empty
// until tasks have been fetched.
std::string task_list_for_new_task_;
// Holds a set of tasks that have been created or updated during the lifetime
// of the provider. These tasks are pushed to the front of the sort order.
base::flat_set<TaskId> created_task_ids_;
// Holds a set of tasks that have been deleted during the lifetime of the
// provider.
base::flat_set<TaskId> deleted_task_ids_;
// Populated when the provider is requesting tasks from the API, otherwise
// empty.
std::unique_ptr<TaskFetcher> task_fetcher_;
// The timestamp of the last task fetch.
base::Time task_fetch_time_;
FocusModeRetryState get_task_retry_state_;
// Retry states for adding and updating tasks.
FocusModeRetryState add_task_retry_state_;
FocusModeRetryState update_task_retry_state_;
base::WeakPtrFactory<FocusModeTasksProvider> weak_factory_{this};
};
} // namespace ash
#endif // ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_TASKS_PROVIDER_H_