chromium/ash/system/focus_mode/focus_mode_chip_carousel.h

// Copyright 2023 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_FOCUS_MODE_FOCUS_MODE_CHIP_CAROUSEL_H_
#define ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_CHIP_CAROUSEL_H_

#include "ash/ash_export.h"
#include "ash/system/focus_mode/focus_mode_tasks_provider.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/layout/box_layout_view.h"

namespace views {
class FlexLayoutView;
class ImageButton;
}  // namespace views

namespace ash {

namespace {
class ChipCarouselScrollView;
}

// A horizontal scroll bar of chips for tasks. Selecting a task chip will save
// it as the currently selected task for the focus session.
class ASH_EXPORT FocusModeChipCarousel : public views::BoxLayoutView {
  METADATA_HEADER(FocusModeChipCarousel, views::BoxLayoutView)
 public:
  // Called when a task chip is pressed, contains a task pointer that is alive
  // for the lifetime of the task chip.
  using ChipPressedCallback =
      base::RepeatingCallback<void(const FocusModeTask& task)>;

  explicit FocusModeChipCarousel(ChipPressedCallback on_chip_pressed);
  FocusModeChipCarousel(const FocusModeChipCarousel&) = delete;
  FocusModeChipCarousel& operator=(const FocusModeChipCarousel&) = delete;
  ~FocusModeChipCarousel() override;

  // TODO(b/305085993): Update setting logic once API is integrated.
  // Updates the carousel of task chips from the first 5 tasks in `tasks` and
  // scrolls the carousel back to the beginning.
  void SetTasks(const std::vector<FocusModeTask>& tasks);

  // Returns whether the carousel is currently displaying any tasks.
  bool HasTasks() const;
  // Returns the number of tasks the carousel is currently showing.
  int GetTaskCountForTesting() const;

  views::ScrollView* GetScrollViewForTesting() const;

  // views::View:
  void Layout(PassKey) override;
  void OnMouseEntered(const ui::MouseEvent& event) override;
  void OnMouseExited(const ui::MouseEvent& event) override;

 private:
  friend class FocusModeChipCarouselTest;

  // Adds or updates the linear gradient on the overflown sides of the carousel.
  void UpdateGradient();

  // Removes the gradient from the `scroll_view_`.
  void RemoveGradient();

  // Scrolls the task chips left if `left` and right otherwise.
  void OnChevronPressed(bool left);

  // Scrolls `scroll_view_` until `chip` is fully in view and aligned with the
  // left side of the non-masked region of the `scroll_view_`. This does not
  // scroll past the end of the carousel.
  void ScrollToChip(views::View* chip);

  raw_ptr<ChipCarouselScrollView> scroll_view_ = nullptr;
  // This view contains the chips for the chip carousel.
  raw_ptr<views::FlexLayoutView> scroll_contents_ = nullptr;
  // The callback to run when a task chip is pressed.
  const ChipPressedCallback on_chip_pressed_;
  // The overflow chevrons.
  raw_ptr<views::ImageButton> left_overflow_icon_ = nullptr;
  raw_ptr<views::ImageButton> right_overflow_icon_ = nullptr;
  // Scroll callbacks are used so we can update chevron and gradient visibility.
  base::CallbackListSubscription on_contents_scrolled_subscription_;
  base::CallbackListSubscription on_contents_scroll_ended_subscription_;
};

}  // namespace ash

#endif  // ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_CHIP_CAROUSEL_H_