chromium/ash/app_list/app_list_bubble_presenter.h

// Copyright 2021 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_APP_LIST_APP_LIST_BUBBLE_PRESENTER_H_
#define ASH_APP_LIST_APP_LIST_BUBBLE_PRESENTER_H_

#include <stdint.h>

#include <memory>
#include <optional>

#include "ash/ash_export.h"
#include "ash/public/cpp/app_list/app_list_types.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_observer.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "ui/display/display_observer.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/wm/public/activation_change_observer.h"

namespace aura {
class Window;
}  // namespace aura

namespace ash {

class AppListBubbleEventFilter;
class AppListBubbleView;
class AppListControllerImpl;
enum class AppListSortOrder;

// Manages the UI for the bubble launcher used in clamshell mode. Handles
// showing and hiding the UI, as well as bounds computations. Only one bubble
// can be visible at a time, across all displays.
class ASH_EXPORT AppListBubblePresenter : public views::WidgetObserver,
                                          public wm::ActivationChangeObserver,
                                          public display::DisplayObserver,
                                          public ShelfObserver {
 public:
  explicit AppListBubblePresenter(AppListControllerImpl* controller);
  AppListBubblePresenter(const AppListBubblePresenter&) = delete;
  AppListBubblePresenter& operator=(const AppListBubblePresenter&) = delete;
  ~AppListBubblePresenter() override;

  // Closes the bubble if it is open and prepares for shutdown.
  void Shutdown();

  // Shows the bubble on the display with `display_id`. The bubble is shown
  // asynchronously (after a delay) because the continue suggestions need to be
  // refreshed before the bubble views can be created and animated. This delay
  // is skipped in unit tests (see TestAppListClient) for convenience. Larger
  // tests (e.g. browser_tests) may need to wait for the window to open.
  void Show(int64_t display_id);

  // Shows or hides the bubble on the display with `display_id`. Returns the
  // appropriate ShelfAction to indicate whether the bubble was shown or hidden.
  ShelfAction Toggle(int64_t display_id);

  // Closes and destroys the bubble.
  void Dismiss();

  // Returns the bubble window or nullptr if it is not open.
  aura::Window* GetWindow() const;

  // Returns true if the bubble is showing on any display.
  bool IsShowing() const;

  // Returns true if the assistant page is showing.
  bool IsShowingEmbeddedAssistantUI() const;

  // Switches to the assistant page. Requires the bubble to be open.
  void ShowEmbeddedAssistantUI();

  // Updates the continue section visibility based on user preference.
  void UpdateContinueSectionVisibility();

  // Handles `AppListController::UpdateAppListWithNewSortingOrder()` for the
  // bubble launcher.
  void UpdateForNewSortingOrder(
      const std::optional<AppListSortOrder>& new_order,
      bool animate,
      base::OnceClosure update_position_closure);

  // views::WidgetObserver:
  void OnWidgetDestroying(views::Widget* widget) override;

  // wm::ActivationChangeObserver:
  void OnWindowActivating(ActivationReason reason,
                          aura::Window* gaining_active,
                          aura::Window* losing_active) override {}
  void OnWindowActivated(ActivationReason reason,
                         aura::Window* gained_active,
                         aura::Window* lost_active) override;

  // DisplayObserver:
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

  // ShelfObserver:
  void OnShelfShuttingDown() override;

  // Returns the preferred width for the bubble launcher for the |root_window|.
  int GetPreferredBubbleWidth(aura::Window* root_window) const;

  views::Widget* bubble_widget_for_test() { return bubble_widget_; }
  AppListBubbleView* bubble_view_for_test() { return bubble_view_; }

 private:
  // Callback for zero state search update. Builds the bubble widget and views
  // on display `display_id` and triggers the show animation.
  void OnZeroStateSearchDone(int64_t display_id);

  // Callback for AppListBubbleEventFilter, used to notify this of presses
  // outside the bubble.
  void OnPressOutsideBubble(const ui::LocatedEvent& event);

  // Gets the display id for the display `bubble_widget_` is shown on. Returns
  // kInvalidDisplayId if not shown.
  int64_t GetDisplayId() const;

  // Callback for the hide animation.
  void OnHideAnimationEnded();

  const raw_ptr<AppListControllerImpl> controller_;

  // Whether the view is showing or animating to show. Note that the
  // `bubble_widget_` may be null during the zero state search called in
  // `Show()`.
  bool is_target_visibility_show_ = false;

  // Owned by native widget.
  raw_ptr<views::Widget> bubble_widget_ = nullptr;

  // Owned by views.
  raw_ptr<AppListBubbleView> bubble_view_ = nullptr;

  // The page to show after the views are constructed.
  AppListBubblePage target_page_ = AppListBubblePage::kApps;

  // Closes the widget when the user clicks outside of it.
  std::unique_ptr<AppListBubbleEventFilter> bubble_event_filter_;

  // Observes display configuration changes.
  display::ScopedDisplayObserver display_observer_{this};

  base::ScopedObservation<Shelf, ShelfObserver> shelf_observer_{this};

  base::WeakPtrFactory<AppListBubblePresenter> weak_factory_{this};
};

}  // namespace ash

#endif  // ASH_APP_LIST_APP_LIST_BUBBLE_PRESENTER_H_