chromium/ash/system/focus_mode/focus_mode_detailed_view.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_DETAILED_VIEW_H_
#define ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_DETAILED_VIEW_H_

#include "ash/ash_export.h"
#include "ash/system/focus_mode/focus_mode_controller.h"
#include "ash/system/focus_mode/focus_mode_task_view.h"
#include "ash/system/model/clock_observer.h"
#include "ash/system/tray/tray_detailed_view.h"
#include "base/timer/timer.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/view_observer.h"

namespace views {
class BoxLayoutView;
class Label;
}  // namespace views

namespace ash {

class FocusModeCountdownView;
class FocusModeSoundsView;
class FocusModeTaskView;
class HoverHighlightView;
class IconButton;
class RoundedContainer;
class Switch;
class SystemTextfield;

// This view displays the focus panel settings that a user can set.
class ASH_EXPORT FocusModeDetailedView : public TrayDetailedView,
                                         public FocusModeController::Observer,
                                         public views::ViewObserver,
                                         public ClockObserver {
  METADATA_HEADER(FocusModeDetailedView, TrayDetailedView)

 public:
  // Ids to easily find child views in `FocusModeDetailedView`. Unique only
  // within the `FocusModeDetailedView`.
  enum ViewId {
    kTimerView = 1000,
    kTaskView,
    kSoundView,
    kTimerTextfield,
    kToggleFocusButton
  };

  explicit FocusModeDetailedView(DetailedViewDelegate* delegate);
  FocusModeDetailedView(const FocusModeDetailedView&) = delete;
  FocusModeDetailedView& operator=(const FocusModeDetailedView&) = delete;
  ~FocusModeDetailedView() override;

  // views::ViewObserver:
  void OnViewBoundsChanged(View* observed_view) override;

  // ClockObserver:
  void OnDateFormatChanged() override;
  void OnSystemClockTimeUpdated() override;
  void OnSystemClockCanSetTimeChanged(bool can_set_time) override;
  void Refresh() override;

 private:
  class TimerTextfieldController;

  friend class FocusModeDetailedViewTest;

  // TrayDetailedView:
  void HandleViewClicked(views::View* view) override {}
  void AddedToWidget() override;

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

  // Creates the row with functionality to start and stop focus mode.
  void CreateToggleView();

  // Updates the accessibility text of the toggle button based on whether focus
  // is in session and the current session duration.
  void UpdateToggleButtonAccessibility(bool in_focus_session);

  // Updates the accessibility text of the timer adjustment buttons.
  void UpdateTimerAdjustmentButtonAccessibility();

  // Creates the row with the timer and functionality to add time to the focus
  // session.
  void CreateTimerView();

  // Updates the row with the timer and functionality to add time to the focus
  // session based on whether focus is in session.
  void UpdateTimerView(bool in_focus_session);

  // Clear the focus for `timer_textfield_` when it's be inactive and update the
  // session duration.
  void HandleTextfieldActivationChange();

  // Creates the row with the task elements. Creates the textfield to allow a
  // user to manually input a task and creates a chip carousel list of tasks to
  // allow the user to select a task. Once the user enters a task in the
  // textfield or selects a task from the list, this view only shows the
  // selected saved task item view and the header.
  void CreateTaskView(bool is_network_connected);

  // Performs an animation to shift the visible container views below
  // `task_view_container_`.
  void OnTaskViewAnimate(const int shift_height);

  // Creates the DND rounded container. This view will be visible only when
  // there is no active focus session. The toggle button in this view will
  // represent if we should toggle on the system DND state for a new focus
  // session.
  void CreateDoNotDisturbContainer();

  // Handles clicks on the do not disturb toggle button.
  void OnDoNotDisturbToggleClicked();

  // Called whenever `clock_timer_` finishes running to update the subheading
  // and reset the clock timer for the next minute.
  void OnClockMinutePassed();

  // Starts `clock_timer_`.
  void StartClockTimer();

  // Increments or decrements the session duration by one step.
  // This is only used outside of a focus session.
  void AdjustInactiveSessionDuration(bool decrement);

  // Called whenever the session duration is adjusted. Updates the labels and
  // button visibilities in the timer setting view.
  void UpdateTimerSettingViewUI();

  // Sets the session duration for the focus controller and calls
  // `UpdateTimerSettingViewUI`.
  void SetInactiveSessionDuration(base::TimeDelta duration);

  // Updates the `toggle_view_` sub text if a focus session is active and
  // `end_time_label_` if it isn't.
  void UpdateEndTimeLabel();

  // This view contains a description of the focus session, as well as a toggle
  // button for staring/ending focus mode.
  raw_ptr<HoverHighlightView> toggle_view_ = nullptr;
  // This view contains the timer view for the user to adjust the focus session
  // duration.
  raw_ptr<RoundedContainer> timer_view_container_ = nullptr;
  // The countdown view inside `timer_view_container_` when focus is in session.
  raw_ptr<FocusModeCountdownView> timer_countdown_view_ = nullptr;
  // This view contains the timer view for the user to adjust the focus session
  // duration when we are not in a focus session.
  raw_ptr<views::BoxLayoutView> timer_setting_view_ = nullptr;
  // Textfield that the user can use to set the timer duration.
  raw_ptr<SystemTextfield> timer_textfield_ = nullptr;
  // Handles input validation and events for the `timer_textfield`.
  std::unique_ptr<TimerTextfieldController> timer_textfield_controller_;
  // The decrement and increment buttons in the `timer_setting_view_`.
  raw_ptr<IconButton> timer_decrement_button_ = nullptr;
  raw_ptr<IconButton> timer_increment_button_ = nullptr;
  // The visual "minutes" label that pairs with the `timer_textfield_` timer
  // duration.
  raw_ptr<views::Label> minutes_label_ = nullptr;
  // A label that displays the end time of the focus session when focus is
  // not active.
  raw_ptr<views::Label> end_time_label_ = nullptr;

  // Records the height of the `task_view_container_`.
  int task_view_container_height_ = 0;
  // The view contains a header view and a `focus_mode_task_view_`.
  raw_ptr<RoundedContainer> task_view_container_ = nullptr;
  raw_ptr<FocusModeTaskView> focus_mode_task_view_ = nullptr;
  raw_ptr<FocusModeSoundsView> focus_mode_sounds_view_ = nullptr;

  // This view contains a toggle for turning on/off DND.
  raw_ptr<RoundedContainer> do_not_disturb_view_ = nullptr;
  raw_ptr<Switch> do_not_disturb_toggle_button_ = nullptr;

  // Updates `end_time_label_` so that it can correctly show what time the focus
  // mode session will end. This is activated when the panel is open but focus
  // mode is not active, because we still need to update the label to say what
  // time the focus mode session would end. In order to track this, this timer
  // fires when the clock minute changes.
  base::OneShotTimer clock_timer_;

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

}  // namespace ash

#endif  // ASH_SYSTEM_FOCUS_MODE_FOCUS_MODE_DETAILED_VIEW_H_