chromium/ash/system/notification_center/views/message_view_container.h

// Copyright 2024 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_NOTIFICATION_CENTER_VIEWS_MESSAGE_VIEW_CONTAINER_H_
#define ASH_SYSTEM_NOTIFICATION_CENTER_VIEWS_MESSAGE_VIEW_CONTAINER_H_

#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/message_center/views/message_view.h"
#include "ui/views/view.h"

namespace message_center {
class Notification;
}  // namespace message_center

namespace ash {

class NotificationListView;
class NotificationSwipeControlView;

// Container view for `MessageView` objects, which are initialized with a
// `message_center::Notification`.
class MessageViewContainer : public views::View,
                             public message_center::MessageView::Observer {
  METADATA_HEADER(MessageViewContainer, views::View)

 public:
  explicit MessageViewContainer(
      std::unique_ptr<message_center::MessageView> message_view,
      NotificationListView* list_view = nullptr);
  MessageViewContainer(const MessageViewContainer&) = delete;
  MessageViewContainer& operator=(const MessageViewContainer&) = delete;
  ~MessageViewContainer() override = default;

  // Calls `GetHeightForWidth` on the cached `message_view_`.
  int CalculateHeight() const;

  // Updates the corner radius based on if the view is at the top or the bottom
  // of its parent list view. If `force_update` is true, the corner radius and
  // background will be updated even if `is_top` and `is_bottom` have the same
  // value as the stored variables.
  void UpdateBorder(const bool is_top,
                    const bool is_bottom,
                    const bool force_update = false);

  // Gets the `notification_id` stored in `message_view_`.
  const std::string GetNotificationId() const;

  // Forwards call to `UpdateWithNotification` in `message_view_`.
  void UpdateWithNotification(const message_center::Notification& notification);

  message_center::MessageView* message_view() { return message_view_; }
  const message_center::MessageView* message_view() const {
    return message_view_;
  }

  base::TimeDelta GetBoundsAnimationDuration() const;

  void SetExpandedBySystem(bool expanded);

  void SlideOutAndClose();

  void CloseSwipeControl();

  // Allows NotificationListView to force preferred size to change during
  // animations.
  void TriggerPreferredSizeChangedForAnimation();

  // views::View:
  gfx::Size CalculatePreferredSize(
      const views::SizeBounds& available_size) const override;
  void ChildPreferredSizeChanged(views::View* child) override;

  // MessageView::Observer:
  void OnSlideChanged(const std::string& notification_id) override;
  void OnSlideEnded(const std::string& notification_id) override;
  void OnPreSlideOut(const std::string& notification_id) override;
  void OnSlideOut(const std::string& notification_id) override;

  void set_start_bounds(const gfx::Rect& start_bounds) {
    start_bounds_ = start_bounds;
  }

  void set_target_bounds(const gfx::Rect& target_bounds) {
    target_bounds_ = target_bounds;
  }

  void set_is_removed(bool is_removed) { is_removed_ = is_removed; }

  void set_needs_bounds_animation(bool needs_bounds_animation) {
    needs_bounds_animation_ = needs_bounds_animation;
  }

  void set_disable_default_background(bool disable_default_background) {
    disable_default_background_ = disable_default_background;
  }

  void set_need_update_corner_radius(bool need_update_corner_radius) {
    need_update_corner_radius_ = need_update_corner_radius;
  }

  gfx::Rect start_bounds() const { return start_bounds_; }
  gfx::Rect target_bounds() const { return target_bounds_; }
  bool is_removed() const { return is_removed_; }
  bool needs_bounds_animation() const { return needs_bounds_animation_; }
  bool is_slid_out() { return is_slid_out_; }

  // Returns if the notification is pinned i.e. can be removed manually.
  bool IsPinned() const;

  // Returns if the notification is a parent of other grouped notifications.
  bool IsGroupParent() const;

  // Returns the direction that the notification is swiped out. If swiped to the
  // left, it returns -1 and if sipwed to the right, it returns 1. By default
  // (i.e. the notification is removed but not by touch gesture), it returns 1.
  int GetSlideDirection() const {
    return message_view_->GetSlideAmount() < 0 ? -1 : 1;
  }

  bool is_top() { return is_top_; }
  bool is_bottom() { return is_bottom_; }

 private:
  // Used to track if this view is at the top or bottom of its parent list view
  // and prevent unnecessary updates.
  bool is_top_ = false;
  bool is_bottom_ = false;

  // Cached to return to previous state after slide animation ends.
  bool previous_is_bottom_ = false;
  bool previous_is_top_ = false;

  // The bounds that the container starts animating from. If not animating, it's
  // ignored.
  gfx::Rect start_bounds_;

  // The final bounds of the container. If not animating, it's same as the
  // actual bounds().
  gfx::Rect target_bounds_;

  // True when the notification is removed and during slide out animation.
  bool is_removed_ = false;

  // True if the notification is slid out completely.
  bool is_slid_out_ = false;

  // True if the notification is slid out through SlideOutAndClose()
  // programagically. False if slid out manually by the user.
  bool is_slid_out_programatically_ = false;

  // Whether expanded state is being set programmatically. Used to prevent
  // animating programmatic expands which occur on open.
  bool expanding_by_system_ = false;

  // Set to flag the view as requiring an expand or collapse animation.
  bool needs_bounds_animation_ = false;

  // `need_update_corner_radius_` indicates that we need to update the corner
  // radius of the view when sliding.
  bool need_update_corner_radius_ = true;

  // Indicates if this view should not draw a background, used for custom
  // notification views which handle their own background.
  bool disable_default_background_ = false;

  // Owned by the views hierarchy.
  const raw_ptr<NotificationListView> list_view_;
  raw_ptr<NotificationSwipeControlView> control_view_;
  raw_ptr<message_center::MessageView> message_view_;
};

}  // namespace ash

#endif  // ASH_SYSTEM_NOTIFICATION_CENTER_VIEWS_MESSAGE_VIEW_CONTAINER_H_