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

ash / system / focus_mode / focus_mode_tray.h [blame]

// 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_TRAY_H_
#define ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_TRAY_H_

#include "ash/ash_export.h"
#include "ash/system/focus_mode/focus_mode_controller.h"
#include "ash/system/focus_mode/focus_mode_countdown_view.h"
#include "ash/system/focus_mode/focus_mode_ending_moment_view.h"
#include "ash/system/focus_mode/focus_mode_tasks_model.h"
#include "ash/system/tray/tray_background_view.h"
#include "base/scoped_observation.h"
#include "ui/base/metadata/metadata_header_macros.h"

namespace views {
class ImageButton;
}

namespace ash {

class ProgressIndicator;
class TrayBubbleWrapper;

// Status area tray which is visible when focus mode is enabled. A circular
// progress bar is displayed around the tray displaying how much time is left in
// the focus session. The tray also controls a bubble that is shown when the
// button is clicked.
class ASH_EXPORT FocusModeTray : public TrayBackgroundView,
                                 public FocusModeController::Observer,
                                 public FocusModeTasksModel::Observer {
  METADATA_HEADER(FocusModeTray, TrayBackgroundView)

 public:
  explicit FocusModeTray(Shelf* shelf);
  FocusModeTray(const FocusModeTray&) = delete;
  FocusModeTray& operator=(const FocusModeTray&) = delete;
  ~FocusModeTray() override;

  // TrayBackgroundView:
  void ClickedOutsideBubble(const ui::LocatedEvent& event) override;
  std::u16string GetAccessibleNameForBubble() override;
  void HandleLocaleChange() override {}
  void HideBubbleWithView(const TrayBubbleView* bubble_view) override;
  void HideBubble(const TrayBubbleView* bubble_view) override;
  TrayBubbleView* GetBubbleView() override;
  void CloseBubbleInternal() override;
  void ShowBubble() override;
  void UpdateTrayItemColor(bool is_active) override;
  void OnThemeChanged() override;
  void OnAnimationEnded() override;

  // FocusModeController::Observer:
  void OnFocusModeChanged(FocusModeSession::State session_state) override;
  void OnTimerTick(const FocusModeSession::Snapshot& session_snapshot) override;
  void OnActiveSessionDurationChanged(
      const FocusModeSession::Snapshot& session_snapshot) override;

  // FocusModeTasksModel::Observer:
  void OnSelectedTaskChanged(const std::optional<FocusModeTask>& task) override;
  void OnTasksUpdated(const std::vector<FocusModeTask>& tasks) override;
  void OnTaskCompleted(const FocusModeTask& completed_task) override;

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

  views::ImageView* image_view() { return image_view_; }

  // Triggers the tray bounce in animation. This is used during the ending
  // moment to notify the user that their session is over. When the animation
  // finishes, the ending moment nudge is then shown.
  void MaybePlayBounceInAnimation();

  FocusModeCountdownView* countdown_view_for_testing() {
    return countdown_view_;
  }
  FocusModeEndingMomentView* ending_moment_view_for_testing() {
    return ending_moment_view_;
  }
  const views::ImageButton* GetRadioButtonForTesting() const;
  const views::Label* GetTaskTitleForTesting() const;

 private:
  friend class FocusModeTrayTest;

  // TODO(b/314022131): Move `TaskItemView` to its own files.
  class TaskItemView;

  // Helper function for creating and setting up the `TaskItemView`.
  void CreateTaskItemView(const std::string& task_title);

  // Updates the image and color of the icon.
  void UpdateTrayIcon();

  // Button click handler for shelf icon.
  void FocusModeIconActivated(const ui::Event& event);

  void UpdateBubbleViews(const FocusModeSession::Snapshot& session_snapshot);

  // Calls `UpdateUI` on `countdown_view_` if it exists and is visible.
  void MaybeUpdateCountdownViewUI(
      const FocusModeSession::Snapshot& session_snapshot);

  // Calls `UpdateUI` on `ending_moment_view_` if it exists and is visible.
  void MaybeUpdateEndingMomentViewUI(
      const FocusModeSession::Snapshot& session_snapshot);

  // Called when the user clicks the radio button to mark a selected task as
  // completed, or if the task is already completed when we show the bubble.
  // `update` is used to determine if we need to update the tasks provider (i.e.
  // we don't if the task is already marked as completed).
  void HandleCompleteTaskButton();

  // Perform the UI update to dismiss the task view.
  void OnClearTask();

  // Called when the animation in `AnimateBubbleResize` starts.
  void OnBubbleResizeAnimationStarted();
  // Called when the animation in `AnimateBubbleResize` ends.
  void OnBubbleResizeAnimationEnded();
  // Animates resizing the bubble view after `task_item_view_` has been removed
  // from the bubble.
  void AnimateBubbleResize();
  // Updates the progression of the progress indicator.
  void UpdateProgressRing();

  // Returns whether the event is located specifically on this focus mode tray
  // view.
  bool EventTargetsTray(const ui::LocatedEvent& event) const;

  // Handles all the cleanup logic associated with closing the bubble, and may
  // reset the focus session if conditions are met. This helper function is
  // mainly used to prevent resetting the focus session when using
  // multi-displays during the ending moment.
  void CloseBubbleAndMaybeReset(bool should_reset);

  // Updates the tray's accessible name in the Views accessibility cache.
  void UpdateAccessibleName();

  // This is used to track the current session snapshot, if any.
  std::optional<FocusModeSession::Snapshot> session_snapshot_;

  // Image view of the focus mode lamp.
  const raw_ptr<views::ImageView> image_view_;

  // The main content view of the bubble.
  raw_ptr<FocusModeCountdownView> countdown_view_ = nullptr;
  raw_ptr<FocusModeEndingMomentView> ending_moment_view_ = nullptr;

  // A box layout view which has a radio/check icon and a label for a selected
  // task.
  raw_ptr<TaskItemView> task_item_view_ = nullptr;

  // `TaskId` of the selected task shown in the `task_item_view_` if it exists.
  std::optional<TaskId> selected_task_;

  raw_ptr<views::BoxLayoutView> bubble_view_container_ = nullptr;

  // The bubble that appears after clicking the tray button.
  std::unique_ptr<TrayBubbleWrapper> bubble_;

  // An object that draws and updates the progress ring.
  std::unique_ptr<ProgressIndicator> progress_indicator_;

  // True to show the progress ring after the pulse animation of
  // `progress_indicator_`.
  bool show_progress_ring_after_animation_ = false;

  // True when the bounce in animation of the tray is done during the ending
  // moment; it will be reset to false when starting or ending a focus session,
  // or extending a focus session during the ending moment.
  bool bounce_in_animation_finished_ = false;

  // The percentage threshold that the session progress needs to exceed in order
  // to trigger a progress ring paint.
  double progress_ring_update_threshold_ = 0.0;

  base::ScopedObservation<FocusModeTasksModel, FocusModeTasksModel::Observer>
      tasks_observation_{this};

  base::WeakPtrFactory<FocusModeTray> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_TRAY_H_