chromium/ash/system/focus_mode/focus_mode_feature_pod_controller.cc

// 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.

#include "ash/system/focus_mode/focus_mode_feature_pod_controller.h"

#include "ash/constants/ash_features.h"
#include "ash/constants/quick_settings_catalogs.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/focus_mode/focus_mode_controller.h"
#include "ash/system/focus_mode/focus_mode_session.h"
#include "ash/system/focus_mode/focus_mode_util.h"
#include "ash/system/unified/feature_tile.h"
#include "ash/system/unified/unified_system_tray_controller.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/i18n/time_formatting.h"
#include "base/time/time.h"
#include "ui/base/l10n/l10n_util.h"

namespace ash {

FocusModeFeaturePodController::FocusModeFeaturePodController(
    UnifiedSystemTrayController* tray_controller)
    : tray_controller_(tray_controller) {
  CHECK(features::IsFocusModeEnabled());
  FocusModeController::Get()->AddObserver(this);
}

FocusModeFeaturePodController::~FocusModeFeaturePodController() {
  FocusModeController::Get()->RemoveObserver(this);
}

std::unique_ptr<FeatureTile> FocusModeFeaturePodController::CreateTile(
    bool compact) {
  auto tile = std::make_unique<FeatureTile>(
      base::BindRepeating(&FocusModeFeaturePodController::OnLabelPressed,
                          weak_factory_.GetWeakPtr()));
  tile_ = tile.get();

  const auto* session_controller = Shell::Get()->session_controller();
  std::optional<user_manager::UserType> user_type =
      session_controller->GetUserType();
  // Only show the focus mode tile if it is a regular user or if the user
  // session is not blocked (e.g. lock screen).
  const bool should_show_tile =
      (user_type && (*user_type == user_manager::UserType::kRegular ||
                     *user_type == user_manager::UserType::kChild)) &&
      !session_controller->IsUserSessionBlocked();

  tile_->SetVisible(should_show_tile);
  if (should_show_tile) {
    TrackVisibilityUMA();
  }

  tile_->SetIconClickable(true);
  tile_->SetIconClickCallback(
      base::BindRepeating(&FocusModeFeaturePodController::OnIconPressed,
                          weak_factory_.GetWeakPtr()));
  tile_->CreateDecorativeDrillInArrow();
  tile_->SetVectorIcon(kFocusModeLampIcon);
  tile_->icon_button()->SetFlipCanvasOnPaintForRTLUI(false);
  auto* controller = FocusModeController::Get();
  tile_->SetToggled(controller->in_focus_session());
  UpdateUI(controller->GetSnapshot(base::Time::Now()));
  return tile;
}

QsFeatureCatalogName FocusModeFeaturePodController::GetCatalogName() {
  return QsFeatureCatalogName::kFocusMode;
}

void FocusModeFeaturePodController::OnIconPressed() {
  auto* controller = FocusModeController::Get();

  // As part of the first time user flow, if the user has never started a
  // session before, we want to direct them to the focus panel so they can get
  // more context and change focus settings instead of starting a session
  // immediately.
  if (!controller->HasStartedSessionBefore()) {
    OnLabelPressed();
    return;
  }

  TrackToggleUMA(/*target_toggle_state=*/!controller->in_focus_session());
  controller->ToggleFocusMode(
      focus_mode_histogram_names::ToggleSource::kFeaturePod);
}

void FocusModeFeaturePodController::OnLabelPressed() {
  TrackDiveInUMA();
  tray_controller_->ShowFocusModeDetailedView();
}

void FocusModeFeaturePodController::OnFocusModeChanged(bool in_focus_session) {
  UpdateUI(FocusModeController::Get()->GetSnapshot(base::Time::Now()));
  tile_->SetToggled(in_focus_session);
}

void FocusModeFeaturePodController::OnTimerTick(
    const FocusModeSession::Snapshot& session_snapshot) {
  UpdateUI(session_snapshot);
}

void FocusModeFeaturePodController::OnInactiveSessionDurationChanged(
    const base::TimeDelta& session_duration) {
  CHECK(tile_);

  if (!FocusModeController::Get()->HasStartedSessionBefore()) {
    return;
  }

  const std::u16string duration_string = focus_mode_util::GetDurationString(
      session_duration, /*digital_format=*/false);
  tile_->SetSubLabel(duration_string);
  tile_->SetTooltipText(l10n_util::GetStringFUTF16(
      IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_INACTIVE, duration_string));
  tile_->SetIconButtonTooltipText(l10n_util::GetStringFUTF16(
      IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_BUTTON_INACTIVE, duration_string));
}

void FocusModeFeaturePodController::OnActiveSessionDurationChanged(
    const FocusModeSession::Snapshot& session_snapshot) {
  UpdateUI(session_snapshot);
}

void FocusModeFeaturePodController::UpdateUI(
    const FocusModeSession::Snapshot& session_snapshot) {
  auto* controller = FocusModeController::Get();
  CHECK(controller);
  CHECK(tile_);

  const bool in_focus_session =
      session_snapshot.state == FocusModeSession::State::kOn;
  tile_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_FOCUS_MODE));

  // As part of the first time user flow, if the user has never started a
  // session before, we hide the session duration sublabel since they are not
  // able to start a focus session immediately anyway.
  if (!controller->HasStartedSessionBefore()) {
    const std::u16string tooltip_text =
        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_INITIAL);
    tile_->SetTooltipText(tooltip_text);
    tile_->SetIconButtonTooltipText(tooltip_text);
    tile_->SetSubLabelVisibility(false);
    tile_->SetIconClickable(false);
    return;
  }

  const base::TimeDelta session_duration_remaining =
      in_focus_session ? session_snapshot.remaining_time
                       : controller->GetSessionDuration();
  const std::u16string duration_string = focus_mode_util::GetDurationString(
      session_duration_remaining, /*digital_format=*/false);
  tile_->SetSubLabel(
      in_focus_session
          ? l10n_util::GetStringFUTF16(
                IDS_ASH_STATUS_TRAY_FOCUS_MODE_TIME_SUBLABEL, duration_string)
          : duration_string);

  const std::u16string tooltip_duration_string =
      session_duration_remaining < base::Minutes(1)
          ? l10n_util::GetStringUTF16(
                IDS_ASH_STATUS_TRAY_FOCUS_MODE_SESSION_LESS_THAN_ONE_MINUTE)
          : duration_string;
  tile_->SetTooltipText(l10n_util::GetStringFUTF16(
      in_focus_session ? IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_ACTIVE
                       : IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_INACTIVE,
      tooltip_duration_string));
  tile_->SetIconClickable(true);
  tile_->SetIconButtonTooltipText(l10n_util::GetStringFUTF16(
      in_focus_session ? IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_BUTTON_ACTIVE
                       : IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_BUTTON_INACTIVE,
      tooltip_duration_string));
}

}  // namespace ash