1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
|
// 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_GLANCEABLES_TASKS_GLANCEABLES_TASKS_VIEW_H_
#define ASH_GLANCEABLES_TASKS_GLANCEABLES_TASKS_VIEW_H_
#include <memory>
#include <optional>
#include "ash/api/tasks/tasks_client.h"
#include "ash/api/tasks/tasks_types.h"
#include "ash/ash_export.h"
#include "ash/glanceables/common/glanceables_time_management_bubble_view.h"
#include "ash/glanceables/glanceables_metrics.h"
#include "ash/glanceables/tasks/glanceables_tasks_error_type.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "google_apis/common/api_error_codes.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/models/list_model.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/views/view.h"
#include "ui/views/view_model.h"
class GURL;
namespace views {
class LabelButton;
} // namespace views
namespace ash {
class GlanceablesTasksComboboxModel;
class GlanceablesTaskView;
// Glanceables view responsible for interacting with Google Tasks.
class ASH_EXPORT GlanceablesTasksView
: public GlanceablesTimeManagementBubbleView {
METADATA_HEADER(GlanceablesTasksView, GlanceablesTimeManagementBubbleView)
public:
explicit GlanceablesTasksView(const ui::ListModel<api::TaskList>* task_lists);
GlanceablesTasksView(const GlanceablesTasksView&) = delete;
GlanceablesTasksView& operator=(const GlanceablesTasksView&) = delete;
~GlanceablesTasksView() override;
// views::View:
void Layout(PassKey) override;
gfx::Size CalculatePreferredSize(
const views::SizeBounds& available_size) const override;
// GlanceablesTimeManagementBubbleView:
void AnimationEnded(const gfx::Animation* animation) override;
// Invalidates any pending tasks, or tasks lists requests. Called when the
// glanceables bubble widget starts closing to avoid unnecessary UI updates.
void CancelUpdates();
// Updates the cached task lists to `task_lists` and the tasks that are
// supposed to show.
void UpdateTaskLists(const ui::ListModel<api::TaskList>* task_lists);
void EndResizeAnimationForTest();
private:
// The context of why the current task list is shown.
enum class ListShownContext {
// The list is a cached one that will be updated later after the lists data
// are fetched.
kCachedList,
// The list that is loaded by default when users open glanceables.
kInitialList,
// The list is manually selected by the users through
// `task_list_combo_box_view_`.
kUserSelectedList
};
// GlanceablesTimeManagementBubbleView:
void OnHeaderIconPressed() override;
void OnFooterButtonPressed() override;
void SelectedListChanged() override;
void AnimateResize(ResizeAnimation::Type resize_type) override;
// Handles press behavior for `add_new_task_button_`.
void AddNewTaskButtonPressed();
// Creates a `GlanceablesTaskView` instance with bound callbacks.
std::unique_ptr<GlanceablesTaskView> CreateTaskView(
const std::string& task_list_id,
const api::Task* task);
// Handles switching between tasks lists.
void ScheduleUpdateTasks(ListShownContext context);
void RetryUpdateTasks(ListShownContext context);
void UpdateTasksInTaskList(
const std::string& task_list_id,
const std::string& task_list_title,
ListShownContext context,
bool fetch_success,
std::optional<google_apis::ApiErrorCode> http_error,
const ui::ListModel<api::Task>* tasks);
// Called as a `state_change_callback` when a task view state changes between
// "view" and "edit" state, which causes changes in the task view preferred
// size. `view_expanding` indicates whether the task view is expanding or
// collapsing in size.
void HandleTaskViewStateChange(bool view_expanding);
// Marks the specified task as completed.
void MarkTaskAsCompleted(const std::string& task_list_id,
const std::string& task_id,
bool completed);
// Handles press behavior for icons that are used to open Google Tasks in the
// browser.
void ActionButtonPressed(TasksLaunchSource source, const GURL& target_url);
// Saves the task (either creates or updates the existing one).
// `view` - individual task view which triggered this request.
// `callback` - done callback passed from an individual task view.
void SaveTask(const std::string& task_list_id,
base::WeakPtr<GlanceablesTaskView> view,
const std::string& task_id,
const std::string& title,
api::TasksClient::OnTaskSavedCallback callback);
// Handles completion of `SaveTask`.
// `view` - individual task view which triggered this request.
// `callback` - callback passed from an individual task view via `SaveTask`.
// `task` - newly created or edited task if the request completes
// successfully, `nullptr` otherwise.
void OnTaskSaved(base::WeakPtr<GlanceablesTaskView> view,
const std::string& task_id,
api::TasksClient::OnTaskSavedCallback callback,
google_apis::ApiErrorCode http_error,
const api::Task* task);
// Returns the current showing task list.
const api::TaskList* GetActiveTaskList() const;
// Creates and shows `error_message_` that depends on the `error_type` and
// `button_action_type`.
void ShowErrorMessageWithType(
GlanceablesTasksErrorType error_type,
ErrorMessageToast::ButtonActionType button_action_type);
// Returns the string to show on `error_message_` according to the
// `error_type`.
std::u16string GetErrorString(GlanceablesTasksErrorType error_type) const;
// Removes `task_view` from the tasks container.
void RemoveTaskView(base::WeakPtr<GlanceablesTaskView> task_view);
// This function should be called with `is_loading` = true if `this` is
// waiting for fetched data to be returned. After the data arrives, resets the
// states by calling with `is_loading` = false.
void SetIsLoading(bool is_loading);
// Animates visibility updates for a task view. It assumes that at most one
// task view changes visibility at the time - currently, this is exclusively
// used for task view added to the list in response to the user clicking the
// button to add a new task.
// When hiding/removing the task view, a copy of the task view layer will
// be created for the animation, so the view can be hidden/removed
// immediately.
void AnimateTaskViewVisibility(views::View* task, bool visible);
void OnTaskViewAnimationCompleted();
// Caching `combobox_model_` from GlanceablesTimeManagementBubbleView.
raw_ptr<GlanceablesTasksComboboxModel> tasks_combobox_model_;
// The number of times that the tasks list has been changed during the
// lifetime of this view.
int tasks_list_change_count_ = 0;
// Whether the first task list has been shown during the lifetime of this
// view.
bool first_task_list_shown_ = false;
// Owned by views hierarchy.
raw_ptr<views::LabelButton> add_new_task_button_ = nullptr;
// An invisible view added at the last element to the task list container to
// more easily track the offset of the bottom of the list from the target
// position mid task view state change animations. The transform will be used
// to synchronize `resize_animation_` with task view resize / task list layout
// animations - if the sentinel, i.e. the bottom of the task list is
// animating, the bubble preferred size will be "offset" by the sentinel
// transform so the bottom of the bubble tracks the bottom of the task list
// (otherwise, if the animations get slightly out of sync, animating task
// views may appear to jitter as their bottom padding changes slightly).
raw_ptr<views::View> task_list_sentinel_ = nullptr;
// Copy of a task view whose visibility is animating to "hidden". The copy
// of the layer is used so the original view can be removed from the view
// hierarchy immediately.
std::unique_ptr<ui::Layer> animating_task_view_layer_;
// The type of resize animation that is currently running.
std::optional<ResizeAnimation::Type> running_resize_animation_ = std::nullopt;
// Records the time when the bubble was about to request a task list. Used for
// metrics.
base::TimeTicks tasks_requested_time_;
// Cached to reset the value of the index of `task_list_combo_box_view_` when
// the target task list failed to be loaded.
std::optional<size_t> cached_selected_list_index_ = std::nullopt;
// Number of tasks added by the user for the currently selected task list.
// Task is considered "added" if task creation was requested via tasks API.
// The count is reset when the selected task list changes.
int added_tasks_ = 0;
// Whether the current task list was empty when it got selected.
bool task_list_initially_empty_ = false;
// Whether the user had a single task list with no tasks when the current task
// list was selected.
bool user_with_no_tasks_ = false;
// Time stamp of when the view was created.
const base::Time shown_time_;
// The model containing task views shown within the tasks bubble. Used to set
// up task view animations in response to a task view change. When animating
// task views, their transform is calculated relative to expected view bounds
// after an imminent layout. The reference/target bounds for the animation
// are cached as view ideal bounds in the model, so the transform can be
// recalculated if another task view state changes before the task list view
// layout gets updated (e.g. if the same user action causes once view to
// transition to kEdit, and another one to kView state).
views::ViewModelT<views::View> task_view_model_;
// Callback that recreates `task_list_combo_box_view_`.
base::OnceClosure recreate_combobox_callback_;
base::WeakPtrFactory<GlanceablesTasksView> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_GLANCEABLES_TASKS_GLANCEABLES_TASKS_VIEW_H_
|