chromium/ash/app_list/views/contents_view.h

// Copyright 2012 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_VIEWS_CONTENTS_VIEW_H_
#define ASH_APP_LIST_VIEWS_CONTENTS_VIEW_H_

#include <map>
#include <memory>
#include <utility>
#include <vector>

#include "ash/ash_export.h"
#include "ash/public/cpp/app_list/app_list_types.h"
#include "ash/public/cpp/pagination/pagination_model.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/view.h"

namespace gfx {
class Rect;
}

namespace ui {
class Layer;
class ScopedLayerAnimationSettings;
}  // namespace ui

namespace ash {

class AppListPage;
class AppListView;
class ApplicationDragAndDropHost;
class AppListMainView;
class AppsContainerView;
class AssistantPageView;
class SearchBoxView;
class SearchResultPageView;

// A view to manage launcher pages within the Launcher (eg. start page, apps
// grid view, search results). There can be any number of launcher pages, only
// one of which can be active at a given time. ContentsView provides the user
// interface for switching between launcher pages, and animates the transition
// between them.
class ASH_EXPORT ContentsView : public views::View,
                                public PaginationModelObserver {
  METADATA_HEADER(ContentsView, views::View)

 public:
  // Used to SetActiveState without animations.
  class ScopedSetActiveStateAnimationDisabler {
   public:
    explicit ScopedSetActiveStateAnimationDisabler(ContentsView* contents_view)
        : contents_view_(contents_view) {
      contents_view_->set_active_state_without_animation_ = true;
    }

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

    ~ScopedSetActiveStateAnimationDisabler() {
      contents_view_->set_active_state_without_animation_ = false;
    }

   private:
    const raw_ptr<ContentsView> contents_view_;
  };

  explicit ContentsView(AppListView* app_list_view);

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

  ~ContentsView() override;

  // Returns the search box top margin when app list view is in peeking/half
  // state, and showing the provided `page`.
  static int GetPeekingSearchBoxTopMarginOnPage(AppListState page);

  // Initialize the pages of the launcher. Should be called after
  // set_contents_switcher_view().
  void Init();

  // Resets the state of the view so it is ready to be shown.
  void ResetForShow();

  // The app list gets closed and drag and drop operations need to be cancelled.
  void CancelDrag();

  // If |drag_and_drop| is not nullptr it will be called upon drag and drop
  // operations outside the application list.
  void SetDragAndDropHostOfCurrentAppList(
      ApplicationDragAndDropHost* drag_and_drop_host);

  // Called when the target state of AppListView changes.
  void OnAppListViewTargetStateChanged(AppListViewState target_state);

  // Shows/hides the search results. Hiding the search results will cause the
  // app list to return to the page that was displayed before
  // ShowSearchResults(true) was invoked.
  void ShowSearchResults(bool show);
  bool IsShowingSearchResults() const;

  // Shows/hides the Assistant page. Hiding the Assistant page will
  // cause the app list to return to the page that was displayed before
  // ShowSearchResults(true) was invoked.
  void ShowEmbeddedAssistantUI(bool show);
  bool IsShowingEmbeddedAssistantUI() const;

  // Sets the active launcher page and animates the pages into place.
  void SetActiveState(AppListState state);
  void SetActiveState(AppListState state, bool animate);

  // The index of the currently active launcher page.
  int GetActivePageIndex() const;

  // The currently active state.
  AppListState GetActiveState() const;

  // True if |state| is the current active laucher page.
  bool IsStateActive(AppListState state) const;

  // Gets the index of a launcher page in |view_model_|, by State. Returns
  // -1 if there is no view for |state|.
  int GetPageIndexForState(AppListState state) const;

  // Gets the state of a launcher page in |view_model_|, by index. Returns
  // INVALID_STATE if there is no state for |index|.
  AppListState GetStateForPageIndex(int index) const;

  int NumLauncherPages() const;

  SearchResultPageView* search_result_page_view() const {
    return search_result_page_view_;
  }
  AppsContainerView* apps_container_view() const {
    return apps_container_view_;
  }
  AppListPage* GetPageView(int index) const;

  SearchBoxView* GetSearchBoxView() const;

  AppListMainView* GetAppListMainView() const;

  AppListView* app_list_view() const { return app_list_view_; }

  // Returns the pagination model for the ContentsView.
  const PaginationModel& pagination_model() { return pagination_model_; }
  PaginationModel* pagination_model_for_testing() { return &pagination_model_; }

  // Returns the search box bounds to use for a given app list (pagination)
  // state (in the current app list view state).
  gfx::Rect GetSearchBoxBounds(AppListState state) const;

  // Returns the search box bounds size to use for a given app list (pagination)
  // state (in the current app list view state).
  gfx::Size GetSearchBoxSize(AppListState state) const;

  // Performs the 'back' action for the active page. Returns whether the action
  // was handled.
  bool Back();

  // Overridden from views::View:
  void Layout(PassKey) override;

  // Overridden from PaginationModelObserver:
  void TotalPagesChanged(int previous_page_count, int new_page_count) override;
  void SelectedPageChanged(int old_selected, int new_selected) override;
  void TransitionStarted() override;
  void TransitionChanged() override;

  // Updates y position and opacity of the items in this view during dragging.
  void UpdateYPositionAndOpacity();

  std::unique_ptr<ui::ScopedLayerAnimationSettings>
  CreateTransitionAnimationSettings(ui::Layer* layer) const;

  // Adjusts search box view size so it fits within the contents view margins
  // (when centered).
  gfx::Size AdjustSearchBoxSizeToFitMargins(
      const gfx::Size& preferred_size) const;

 private:
  // Sets the active launcher page.
  void SetActiveStateInternal(int page_index, bool animate);

  // Invoked when active view is changed.
  void ActivePageChanged();

  void InitializeSearchBoxAnimation(AppListState current_state,
                                    AppListState target_state);
  void UpdateSearchBoxAnimation(double progress,
                                AppListState current_state,
                                AppListState target_state);

  // Updates search box visibility based on the current state.
  void UpdateSearchBoxVisibility(AppListState current_state);

  // Adds |view| as a new page to the end of the list of launcher pages. The
  // view is inserted as a child of the ContentsView. The page is associated
  // with the name |state|. Returns a pointer to the instance of the new page.
  template <typename T>
  T* AddLauncherPage(std::unique_ptr<T> view, AppListState state) {
    auto* result = view.get();
    AddLauncherPageInternal(std::move(view), state);
    return result;
  }

  // Internal version of the above that does the actual work.
  void AddLauncherPageInternal(std::unique_ptr<AppListPage> view,
                               AppListState state);

  // Returns true if the |page| requires layout when transitioning from
  // |current_state| to |target_state|.
  bool ShouldLayoutPage(AppListPage* page,
                        AppListState current_state,
                        AppListState target_state) const;

  // Converts rect to widget without applying transform.
  gfx::Rect ConvertRectToWidgetWithoutTransform(const gfx::Rect& rect);

  // Sub-views of the ContentsView. All owned by the views hierarchy.
  raw_ptr<AssistantPageView> assistant_page_view_ = nullptr;
  raw_ptr<AppsContainerView> apps_container_view_ = nullptr;
  raw_ptr<SearchResultPageView> search_result_page_view_ = nullptr;

  // The child page views. Owned by the views hierarchy.
  std::vector<raw_ptr<AppListPage, VectorExperimental>> app_list_pages_;

  // Owned by the views hierarchy.
  const raw_ptr<AppListView> app_list_view_;

  // Maps State onto |view_model_| indices.
  std::map<AppListState, int> state_to_view_;

  // Maps |view_model_| indices onto State.
  std::map<int, AppListState> view_to_state_;

  // The page that was showing before ShowSearchResults(true) was invoked.
  int page_before_search_ = 0;

  // Manages the pagination for the launcher pages.
  PaginationModel pagination_model_{this};

  // If true, SetActiveState immediately.
  bool set_active_state_without_animation_ = false;
};

}  // namespace ash

#endif  // ASH_APP_LIST_VIEWS_CONTENTS_VIEW_H_