chromium/ash/system/unified/feature_tiles_container_view.h

// Copyright 2022 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_UNIFIED_FEATURE_TILES_CONTAINER_VIEW_H_
#define ASH_SYSTEM_UNIFIED_FEATURE_TILES_CONTAINER_VIEW_H_

#include "ash/ash_export.h"
#include "ash/public/cpp/pagination/pagination_model_observer.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/view.h"

namespace ash {

class FeatureTile;
class PaginationModel;
class UnifiedSystemTrayController;

// Container of FeatureTiles in the middle of QuickSettingsView.
// It can place buttons in a 1x2 to 4x2 grid given the available height.
// Implements pagination to be able to show all visible FeatureTiles.
class ASH_EXPORT FeatureTilesContainerView : public views::View,
                                             public PaginationModelObserver,
                                             public views::FocusChangeListener {
  METADATA_HEADER(FeatureTilesContainerView, views::View)

 public:
  explicit FeatureTilesContainerView(UnifiedSystemTrayController* controller);

  FeatureTilesContainerView(const FeatureTilesContainerView&) = delete;
  FeatureTilesContainerView& operator=(const FeatureTilesContainerView&) =
      delete;

  ~FeatureTilesContainerView() override;

  // Adds feature tiles to display in the tiles container.
  void AddTiles(std::vector<std::unique_ptr<FeatureTile>> tiles);

  // Lays out the existing tiles into rows. Used when the visibility of a tile
  // changes, which might change the number of required rows.
  void RelayoutTiles();

  // Sets the number of rows of feature tiles based on the max height the
  // container can have.
  void SetRowsFromHeight(int max_height);

  // Caps the number of rows of feature tiles when media view is shown, based on
  // the `max_height` the container can have.
  void AdjustRowsForMediaViewVisibility(bool visible, int max_height);

  // PaginationModelObserver:
  void SelectedPageChanged(int old_selected, int new_selected) override;
  void TransitionChanged() override;

  // views::View:
  void OnGestureEvent(ui::GestureEvent* event) override;
  void OnScrollEvent(ui::ScrollEvent* event) override;
  bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
  void Layout(PassKey) override;
  void AddedToWidget() override;
  void RemovedFromWidget() override;

  // views::FocusChangeListener:
  void OnWillChangeFocus(views::View* before, views::View* now) override;
  void OnDidChangeFocus(views::View* before, views::View* now) override;

  // Returns the number of children that are visible.
  int GetVisibleFeatureTileCount() const;

  int displayable_rows() const { return displayable_rows_; }

  int row_count() { return rows_.size(); }

  int page_count() { return pages_.size(); }

 private:
  friend class FeatureTilesContainerViewTest;
  friend class QuickSettingsViewTest;

  class RowContainer;
  class PageContainer;

  // Calculates the number of rows based on the available `height`.
  int CalculateRowsFromHeight(int height);

  // Calculates and sets the position of the container pages that are animating
  // through a scroll, drag gesture or by clicking on a pagination dot.
  // This function is called multiple times per page transition.
  // After animation ends, `SelectedPageChanged` will be called to update bounds
  // of all pages, including those that were not part of the transition.
  void UpdateAnimatingPagesBounds(int old_selected, int new_selected);

  // Updates page splits for feature tiles.
  void UpdateTotalPages();

  // Owned by `UnifiedSystemTrayBubble`.
  const raw_ptr<UnifiedSystemTrayController> controller_;

  // Owned by `UnifiedSystemTrayModel`.
  const raw_ptr<PaginationModel> pagination_model_;

  // List of pages that contain `RowContainer` elements.
  // Owned by views hierarchy.
  std::vector<raw_ptr<PageContainer, VectorExperimental>> pages_;

  // List of rows that contain `FeatureTile` elements.
  // Owned by views hierarchy.
  std::vector<raw_ptr<RowContainer, VectorExperimental>> rows_;

  // Number of rows that can be displayed based on the available
  // max height.
  int displayable_rows_ = 0;

  bool is_media_view_shown_ = false;

  // Used for preventing reentrancy issue in ChildVisibilityChanged. Should be
  // always false if FeatureTilesContainerView is not in the call stack.
  bool changing_visibility_ = false;
};

}  // namespace ash

#endif  // ASH_SYSTEM_UNIFIED_FEATURE_TILES_CONTAINER_VIEW_H_