chromium/ash/public/cpp/system/anchored_nudge_data.h

// 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_PUBLIC_CPP_SYSTEM_ANCHORED_NUDGE_DATA_H_
#define ASH_PUBLIC_CPP_SYSTEM_ANCHORED_NUDGE_DATA_H_

#include <optional>
#include <string>

#include "ash/constants/notifier_catalogs.h"
#include "ash/public/cpp/ash_public_export.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/time/time.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/view_tracker.h"

namespace views {
class View;
class Widget;
}  // namespace views

namespace ash {

// Refer to `anchored_nudge_manager_impl.cc` to see the duration values.
// TODO(b/297619385): Move constants to a new constants file.
enum class NudgeDuration {
  // Default duration that is used for nudges that expire.
  kDefaultDuration = 0,

  // Used for nudges with a button or a body text that has
  // `AnchoredNudgeManagerImpl::kLongBodyTextLength` or more characters.
  kMediumDuration = 1,

  // Used for nudges that are meant to persist until user interacts with them.
  kLongDuration = 2,

  kMaxValue = kLongDuration
};

using HoverChangedCallback = base::RepeatingCallback<void(bool is_hovered)>;
using NudgeClickCallback = base::RepeatingCallback<void()>;
using NudgeDismissCallback = base::RepeatingCallback<void()>;

// Describes the contents of a System Nudge (AnchoredNudge), which is a notifier
// that informs users about something that might enhance their experience. See
// the "Educational Nudges" section in go/notifier-framework for example usages.
// Nudges may anchor to any `views::View` on screen and will follow it to set
// its bounds. Nudges with no `anchor_view` will show in the default location.
// Nudges `anchored_to_shelf` will set their arrow based on the shelf alignment.
// TODO(b/285988235): `AnchoredNudge` will replace the existing `SystemNudge`
// and take over its name.
struct ASH_PUBLIC_EXPORT AnchoredNudgeData {
  AnchoredNudgeData(const std::string& id,
                    NudgeCatalogName catalog_name,
                    const std::u16string& body_text,
                    views::View* anchor_view = nullptr);
  AnchoredNudgeData(AnchoredNudgeData&& other);
  AnchoredNudgeData& operator=(AnchoredNudgeData&& other);
  ~AnchoredNudgeData();

  views::View* GetAnchorView() const { return anchor_view_tracker_->view(); }
  bool is_anchored() const { return is_anchored_; }

  // Sets the anchor view, observes it with a view tracker to assign a nullptr
  // in case the view is deleted, and sets the `is_anchored_` member variable.
  void SetAnchorView(views::View* anchor_view);

  // Required system nudge elements.
  std::string id;
  NudgeCatalogName catalog_name;
  std::u16string body_text;

  // Optional system nudge view elements. If not empty, a leading image, nudge
  // title, or keyboard shortcut view will be created and the background will
  // use customized colors.
  ui::ImageModel image_model;
  std::u16string title_text;
  std::vector<ui::KeyboardCode> keyboard_codes;
  std::optional<ui::ColorId> background_color_id;
  std::optional<ui::ColorId> image_background_color_id;

  // Callback for close button pressed.
  base::RepeatingClosure close_button_callback;

  // Optional system nudge buttons. If the text is not empty, the respective
  // button will be created. Pressing the button will execute its callback, if
  // any, followed by the nudge being closed. `secondary_button_text` should
  // only be set if `primary_button_text` has also been set.
  // TODO(b/285023559): Add a `ChainedCancelCallback` class instead of a
  // `RepeatingClosure` so we don't have to manually modify the provided
  // callbacks in the manager.
  std::u16string primary_button_text;
  base::RepeatingClosure primary_button_callback = base::DoNothing();

  std::u16string secondary_button_text;
  base::RepeatingClosure secondary_button_callback = base::DoNothing();

  // Used to set the nudge's placement in relation to the anchor view, if any.
  views::BubbleBorder::Arrow arrow = views::BubbleBorder::BOTTOM_RIGHT;

  // Nudges can set a default, medium or long duration for nudges that persist.
  // Refer to `anchored_nudge_manager_impl.cc` to see the duration values.
  // TODO(b/297619385): Move constants to a new constants file.
  NudgeDuration duration = NudgeDuration::kDefaultDuration;

  // If true, `arrow` will be set based on the current shelf alignment, and the
  // nudge will listen to shelf alignment changes to readjust its `arrow`.
  // It will maintain the shelf visible while a nudge is being shown.
  bool anchored_to_shelf = false;

  // Whether the image will be set to the same size as its container view. This
  // is required for lottie images, which need their size to be set directly.
  bool fill_image_size = false;

  // Highlight anchor button by default.
  bool highlight_anchor_button = true;

  // If true, set the `anchor_view` as parent.
  bool set_anchor_view_as_parent = false;

  // If false, the ChromeVox will not announce `body_text`.
  bool announce_chromevox = true;

  // If not null, the nudge will anchor inside the `anchor_widget`, which is a
  // `views::Widget`. Used together with the `views::BubbleBorder::Arrow`, but
  // currently only support anchoring to the bottom corners of the
  // `anchor_widget`. NOTE: This is a new type of anchoring, which is different
  // than the `anchor_view`. At most only one of them can be set.
  raw_ptr<views::Widget> anchor_widget = nullptr;

  // Nudge action custom callbacks.
  HoverChangedCallback hover_changed_callback;
  NudgeClickCallback click_callback;
  NudgeDismissCallback dismiss_callback;

 private:
  // True if an anchor view is provided when constructing the nudge data object
  // or through the `SetAnchorView` function.
  bool is_anchored_ = false;

  // View tracker that caches a pointer to the anchor view and sets it to
  // nullptr in case the view was deleted.
  std::unique_ptr<views::ViewTracker> anchor_view_tracker_;
};

}  // namespace ash

#endif  // ASH_PUBLIC_CPP_SYSTEM_ANCHORED_NUDGE_DATA_H_