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
ash / glanceables / tasks / glanceables_task_view.h [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.
#ifndef ASH_GLANCEABLES_TASKS_GLANCEABLES_TASK_VIEW_H_
#define ASH_GLANCEABLES_TASKS_GLANCEABLES_TASK_VIEW_H_
#include <string>
#include "ash/api/tasks/tasks_client.h"
#include "ash/api/tasks/tasks_types.h"
#include "ash/ash_export.h"
#include "ash/glanceables/tasks/glanceables_tasks_error_type.h"
#include "ash/style/error_message_toast.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "google_apis/common/api_error_codes.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/layout/flex_layout_view.h"
#include "ui/views/view_observer.h"
namespace views {
class ImageButton;
class ImageView;
class LabelButton;
} // namespace views
namespace ash {
class SystemTextfield;
// `GlanceablesTaskView` uses `views::FlexLayout` to show tasks metadata within
// the `GlanceablesTasksView`.
// +---------------------------------------------------------------+
// |`GlanceablesTaskView` |
// | |
// | +-----------------+ +---------------------------------------+ |
// | |'check_button_' | |'contents_view_' | |
// | | | | +-----------------------------------+ | |
// | | | | |'tasks_title_view_' | | |
// | | | | +-----------------------------------+ | |
// | | | | +-----------------------------------+ | |
// | | | | |'tasks_details_view_' | | |
// | | | | +-----------------------------------+ | |
// | +-----------------+ +---------------------------------------+ |
// +---------------------------------------------------------------+
class ASH_EXPORT GlanceablesTaskView : public views::FlexLayoutView,
public views::ViewObserver {
METADATA_HEADER(GlanceablesTaskView, views::FlexLayoutView)
public:
using MarkAsCompletedCallback =
base::RepeatingCallback<void(const std::string& task_id, bool completed)>;
using SaveCallback = base::RepeatingCallback<void(
base::WeakPtr<GlanceablesTaskView> view,
const std::string& task_id,
const std::string& title,
api::TasksClient::OnTaskSavedCallback callback)>;
using ShowErrorMessageCallback =
base::RepeatingCallback<void(GlanceablesTasksErrorType,
ErrorMessageToast::ButtonActionType)>;
using StateChangeObserverCallback =
base::RepeatingCallback<void(bool view_expanding)>;
// Modes of `tasks_title_view_` (simple label or text field).
enum class TaskTitleViewState { kNotInitialized, kView, kEdit };
GlanceablesTaskView(const api::Task* task,
MarkAsCompletedCallback mark_as_completed_callback,
SaveCallback save_callback,
base::RepeatingClosure edit_in_browser_callback,
ShowErrorMessageCallback show_error_message_callback);
GlanceablesTaskView(const GlanceablesTaskView&) = delete;
GlanceablesTaskView& operator=(const GlanceablesTaskView&) = delete;
~GlanceablesTaskView() override;
void set_state_change_observer(const StateChangeObserverCallback& observer) {
state_change_observer_ = observer;
}
// views::ViewObserver:
void OnViewBlurred(views::View* observed_view) override;
void OnViewIsDeleting(views::View* observed_view) override;
const views::ImageButton* GetCheckButtonForTest() const;
bool GetCompletedForTest() const;
void SetCheckedForTest(bool checked);
// Updates `tasks_title_view_` according to `state`.
void UpdateTaskTitleViewForState(TaskTitleViewState state);
// Sets the network to be connected. This should only be used in tests.
static void SetIsNetworkConnectedForTest(bool connected);
private:
class CheckButton;
class TaskTitleButton;
// Adds additional content (assigned task privacy notice if available + edit
// in browser button) when the view is in edit mode.
void AddExtraContentForEditState();
// Updates the margins of views in `contents_view_`.
void UpdateContentsMargins(TaskTitleViewState state);
// Updates the `extra_content_for_edit_state_` visibility animating its
// opacity. When hiding the container, the container is hidden immediately,
// but copy of its layer is created, and animated in its place.
void AnimateExtraContentForEditStateVisibility(bool visible);
void OnExtraContentForEditStateVisibilityAnimationCompleted();
// Handles press events on `check_button_`.
void CheckButtonPressed();
// Handles press events on `task_title_button_`.
void TaskTitleButtonPressed();
// Handles finished editing event from the text field, updates `task_title_`
// and propagates new `title` to the server.
void OnFinishedEditing(const std::u16string& title);
// Handles completion of running `save_callback_` callback.
// `task` - newly created or updated task.
void OnSaved(google_apis::ApiErrorCode http_error, const api::Task* task);
// Owned by views hierarchy.
raw_ptr<CheckButton> check_button_ = nullptr;
raw_ptr<views::FlexLayoutView> contents_view_ = nullptr;
raw_ptr<views::FlexLayoutView> tasks_title_view_ = nullptr;
raw_ptr<TaskTitleButton> task_title_button_ = nullptr;
raw_ptr<SystemTextfield> task_title_textfield_ = nullptr;
raw_ptr<views::FlexLayoutView> tasks_details_view_ = nullptr;
raw_ptr<views::ImageView> origin_surface_type_icon_ = nullptr;
raw_ptr<views::View> extra_content_for_edit_state_ = nullptr;
raw_ptr<views::LabelButton> edit_in_browser_button_ = nullptr;
// ID for the task represented by this view.
std::string task_id_;
// Title of the task.
std::u16string task_title_;
// The type of surface a task originates from.
api::Task::OriginSurfaceType origin_surface_type_;
// Cached to reset the value of `task_title_` when the new title failed to
// commit after editing.
std::u16string task_title_before_edit_ = u"";
bool saving_task_changes_ = false;
// Marks the task as completed.
const MarkAsCompletedCallback mark_as_completed_callback_;
// Saves the task (either creates or updates the existing one).
const SaveCallback save_callback_;
// `edit_in_browser_button_` callback that opens the Tasks in browser.
const base::RepeatingClosure edit_in_browser_callback_;
// Shows an error message in the parent `GlanceablesTasksView`.
const ShowErrorMessageCallback show_error_message_callback_;
// Callback which, if set, gets called when the task view state changes
// between editing and viewing state.
StateChangeObserverCallback state_change_observer_;
// Copy of `extra_content_for_edit_state_` (assigned task privacy notice if
// available + edit in browser button) layer used for the visibility animation
// when hiding the container. The container gets hidden immediately, and the
// layer is faded out in its place. Deleted when the fade out animation
// completes.
std::unique_ptr<ui::Layer> animating_extra_content_for_edit_state_layer_;
base::ScopedMultiSourceObservation<views::View, GlanceablesTaskView>
edit_exit_observer_{this};
base::WeakPtrFactory<GlanceablesTaskView> state_change_weak_ptr_factory_{
this};
base::WeakPtrFactory<GlanceablesTaskView> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_GLANCEABLES_TASKS_GLANCEABLES_TASK_VIEW_H_