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
|
// 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 <string_view>
#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(std::u16string_view 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_
|