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
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225

ash / wm / overview / birch / birch_bar_view.h [blame]

// 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_WM_OVERVIEW_BIRCH_BIRCH_BAR_VIEW_H_
#define ASH_WM_OVERVIEW_BIRCH_BIRCH_BAR_VIEW_H_

#include "ash/ash_export.h"
#include "ash/wm/overview/birch/birch_chip_button.h"
#include "base/memory/weak_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/layout/box_layout_view.h"

namespace aura {
class Window;
}  // namespace aura

namespace views {
class Widget;
}  // namespace views

namespace ash {

class BirchItem;

// The birch chips bar container holds up to four birch chips. It has a
// responsive layout to adjust the chips position according to the number of
// chips present and the available space. The chips will be in a row if they can
// fit in the space. Otherwise, the chips will be in the 2x2 grids. The birch
// bar has a two levels nested box layout view:
//
// BirchBarView (2x1)
//      |
//      -----Primary Row (1xn)
//      |
//      -----Secondary Row (1xn)
//
// The BirchBarView owns the primary and secondary chips rows, which are both
// horizontal box layout views. The chips will be in the primary row, if they
// fit in the work area. Otherwise, the third and fourth chips will be moved to
// the secondary row.

class ASH_EXPORT BirchBarView : public views::BoxLayoutView {
  METADATA_HEADER(BirchBarView, views::BoxLayoutView)

 public:
  static constexpr int kMaxChipsNum = 4;

  enum class State {
    kLoading,                    // The bar is waiting for data on creation.
    kLoadingForInformedRestore,  // The bar is waiting for data on creation for
                                 // informed restore.
    kLoadingByUser,  // The bar is waiting for data when enabled by user.
    kReloading,      // The bar is waiting for data when suggestion types are
                     // modified.
    kShuttingDown,   // The bar is shutting down when disabled.
    kNormal,         // The bar is showing chips.
  };

  enum class RelayoutReason {
    // Relayout caused by filling in new suggestions after data fetched from
    // model.
    kSetup,
    // Relayout caused by filling in new suggestions when the bar is enabled by
    // user.
    kSetupByUser,
    // Relayout caused by adding or removing chips.
    kAddRemoveChip,
    // Relayout caused by available space change.
    kAvailableSpaceChanged,
    // Relayout caused by clearing chips when the bar is disabled by user.
    kClearOnDisabled,
  };

  // The callback which is called when the birch bar view relayouts due to given
  // reason.
  using RelayoutCallback = base::RepeatingCallback<void(RelayoutReason)>;

  explicit BirchBarView(aura::Window* root_window);
  BirchBarView(const BirchBarView&) = delete;
  BirchBarView& operator=(const BirchBarView&) = delete;
  ~BirchBarView() override;

  // Creates a birch bar widget for given `root_window`.
  static std::unique_ptr<views::Widget> CreateBirchBarWidget(
      aura::Window* root_window);

  const std::vector<raw_ptr<BirchChipButtonBase>>& chips() const {
    return chips_;
  }

  void SetState(State state);

  // Clears the items cached in the `BirchChipButtons`.
  void ShutdownChips();

  // Updates the birch bar's available space and relayout the bar according to
  // the updated available space. Note that the function must be called before
  // getting the view's preferred size.
  void UpdateAvailableSpace(int available_space);

  // Registers a relayout callback.
  void SetRelayoutCallback(RelayoutCallback callback);

  // Gets current number of chips.
  int GetChipsNum() const;

  // Clear existing chips and create new chips with given items.
  void SetupChips(const std::vector<raw_ptr<BirchItem>>& items);

  // Adds a new chip with given item.
  void AddChip(BirchItem* birch_item);

  // Removes the chip of `removed_item` and attaches a new chip with
  // `attached_item` if it's not null.
  void RemoveChip(BirchItem* removed_item, BirchItem* attached_item = nullptr);

  // Re-initializes the chip corresponding to the given `item`.
  void UpdateChip(BirchItem* item);

  // Gets the maximum height of the bar with full chips.
  int GetMaximumHeight() const;

  // Returns if there are on-going animations.
  bool IsAnimating();

 private:
  friend class OverviewGridTestApi;

  // The layouts that the birch bar may use. When current available space can
  // hold all present chips, a 1x4 grids layout is used. Otherwise, a 2x2 grids
  // layout is used.
  enum class LayoutType {
    kOneByFour,
    kTwoByTwo,
  };

  // Creates a chip for given `item`.
  std::unique_ptr<BirchChipButtonBase> CreateChipForItem(BirchItem* item);

  void AttachChip(std::unique_ptr<BirchChipButtonBase> chip);

  // Remove all current chips.
  void Clear();

  // Calculates the chip size according to current shelf position and display
  // size.
  gfx::Size GetChipSize(aura::Window* root_window) const;

  // Gets expected layout types according to the given number of chips and
  // current available space.
  LayoutType GetExpectedLayoutType(int chip_num) const;

  // Rearranges the chips according to current expected layout type.
  void Relayout(RelayoutReason reason);

  // Called after relayout.
  void OnRelayout(RelayoutReason reason);

  // Adds loading chips to show loading animations.
  void AddLoadingChips();

  // Adds reloading chips to show reloading animations.
  void AddReloadingChips();

  // Performs the fade-in animation of chips.
  void FadeInChips();

  // Performs fade-out animation on current chips.
  void FadeOutChips();

  // Called when fade-out animation is aborted.
  void OnFadeOutAborted();

  // Called after chips fading-in animations are done during setting up.
  void OnSetupEnded();

  // Called after chips fading-out animations are done during shutting down.
  void OnShutdownEnded();

  // Called after the removing chip fade-out animation is done.
  void OnRemovingChipFadeOutEnded(BirchChipButtonBase* removing_chip);

  // Called when remove a chip from the bar with the single row.
  void RemoveChipFromOneRowBar(BirchChipButtonBase* removing_chip);

  // Called when remove a chip from the bar with two rows.
  void RemoveChipFromTwoRowsBar(BirchChipButtonBase* removing_chip);

  // Possibly show the privacy nudge about context menu options for
  // controlling suggestion types.
  void MaybeShowPrivacyNudge();

  // Cached chip size.
  const gfx::Size chip_size_;

  // Cached available space.
  int available_space_ = 0;

  // Chips rows owned by this.
  raw_ptr<BoxLayoutView> primary_row_;
  // The secondary row only exists when it holds chips. Otherwise, there will
  // always be child spacing between the rows.
  raw_ptr<BoxLayoutView> secondary_row_ = nullptr;

  State state_ = State::kNormal;

  // The chips are owned by either primary or secondary row.
  std::vector<raw_ptr<BirchChipButtonBase>> chips_;

  // The chips which are waiting to be attached.
  base::circular_deque<std::unique_ptr<BirchChipButtonBase>> chips_to_attach_;

  // Called after relayout.
  RelayoutCallback relayout_callback_;

  // Called after chips fade-out animation.
  base::OnceClosure shutdown_callback_;
};

}  // namespace ash

#endif  // ASH_WM_OVERVIEW_BIRCH_BIRCH_BAR_VIEW_H_