chromium/ash/system/video_conference/bubble/title_view.cc

// Copyright 2024 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/video_conference/bubble/title_view.h"

#include "ash/constants/ash_features.h"
#include "ash/constants/notifier_catalogs.h"
#include "ash/public/cpp/style/color_provider.h"
#include "ash/public/cpp/system/anchored_nudge_data.h"
#include "ash/public/cpp/system/anchored_nudge_manager.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_id.h"
#include "ash/style/typography.h"
#include "ash/system/video_conference/bubble/mic_indicator.h"
#include "ash/system/video_conference/bubble/settings_button.h"
#include "ash/system/video_conference/video_conference_tray_controller.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/color/color_provider.h"
#include "ui/compositor/layer.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/widget/unique_widget_ptr.h"
#include "ui/views/widget/widget.h"

namespace ash::video_conference {

namespace {

constexpr gfx::Size kIconSize{20, 20};
constexpr char kSidetoneNudgeId[] = "video_conference_tray_nudge_ids.sidetone";
constexpr auto kTitleChildSpacing = 8;
constexpr auto kTitleViewPadding = gfx::Insets::TLBR(16, 16, 0, 16);

}  // namespace

TitleView::TitleView() {
  SetOrientation(views::LayoutOrientation::kHorizontal);
  SetInsideBorderInsets(kTitleViewPadding);
  SetCrossAxisAlignment(views::BoxLayout::CrossAxisAlignment::kCenter);
  SetBetweenChildSpacing(kTitleChildSpacing);

  auto* title_column =
      AddChildView(views::Builder<views::BoxLayoutView>()
                       .SetBetweenChildSpacing(kTitleChildSpacing)
                       .Build());

  title_column->AddChildView(
      views::Builder<views::ImageView>()
          .SetImage(ui::ImageModel::FromVectorIcon(
              kSystemMenuVideocamIcon, cros_tokens::kCrosSysOnSurface))
          .SetImageSize(kIconSize)
          .Build());

  auto* title_label = title_column->AddChildView(
      views::Builder<views::Label>()
          .SetText(
              l10n_util::GetStringUTF16(IDS_ASH_VIDEO_CONFERENCE_BUBBLE_TITLE))
          .SetHorizontalAlignment(gfx::ALIGN_LEFT)
          .SetEnabledColorId(kColorAshTextColorPrimary)
          .SetAutoColorReadabilityEnabled(false)
          .Build());

  TypographyProvider::Get()->StyleLabel(TypographyToken::kCrosTitle1,
                                        *title_label);
  SetFlexForView(title_column, 1);

  auto* mic_test_column =
      AddChildView(views::Builder<views::BoxLayoutView>()
                       .SetVisible(VideoConferenceTrayController::Get()
                                       ->GetHasMicrophonePermissions())
                       .Build());

  if (features::IsVcTrayMicIndicatorEnabled()) {
    mic_test_column->AddChildView(std::make_unique<MicIndicator>());
  }

  sidetone_button_ = mic_test_column->AddChildView(std::make_unique<IconButton>(
      base::BindRepeating(&TitleView::OnSidetoneButtonClicked,
                          weak_ptr_factory_.GetWeakPtr()),
      IconButton::Type::kMedium, &kVideoConferenceSidetoneIcon,
      IDS_ASH_VIDEO_CONFERENCE_BUBBLE_SIDETONE_TOGGLE_TOOLTIP,
      /*is_toggleable=*/true,
      /*has_border=*/false));

  sidetone_button_->SetBackgroundColor(SK_ColorTRANSPARENT);
  sidetone_button_->SetBackgroundToggledColor(
      cros_tokens::kCrosSysSystemPrimaryContainer);
  sidetone_button_->SetToggled(
      VideoConferenceTrayController::Get()->GetSidetoneEnabled());

  VideoConferenceTrayController::Get()->UpdateSidetoneSupportedState();

  if (features::IsVcStudioLookEnabled()) {
    AddChildView(std::make_unique<SettingsButton>());
  }
}

void TitleView::OnSidetoneButtonClicked(const ui::Event& event) {
  auto* controller = VideoConferenceTrayController::Get();
  const bool enabled = !controller->GetSidetoneEnabled();

  if (enabled) {
    const bool supported = controller->IsSidetoneSupported();
    ShowSidetoneBubble(supported);

    if (supported) {
      sidetone_button_->SetToggled(enabled);
      controller->SetSidetoneEnabled(enabled);
    }
  } else {
    CloseSidetoneBubble();

    sidetone_button_->SetToggled(enabled);
    controller->SetSidetoneEnabled(enabled);
  }
}

void TitleView::ShowSidetoneBubble(const bool supported) {
  NudgeCatalogName catalog_name =
      supported ? NudgeCatalogName::kVideoConferenceTraySidetoneEnabled
                : NudgeCatalogName::kVideoConferenceTraySidetoneNotSupported;

  std::u16string body_str = l10n_util::GetStringUTF16(
      supported ? IDS_ASH_VIDEO_CONFERENCE_SIDETONE_ENABLED_BUBBLE_BODY
                : IDS_ASH_VIDEO_CONFERENCE_SIDETONE_NOT_SUPPORTED_BUBBLE_BODY);

  AnchoredNudgeData nudge_data(kSidetoneNudgeId, catalog_name, body_str,
                               sidetone_button_);
  nudge_data.title_text = l10n_util::GetStringUTF16(
      supported ? IDS_ASH_VIDEO_CONFERENCE_SIDETONE_ENABLED_BUBBLE_TITLE
                : IDS_ASH_VIDEO_CONFERENCE_SIDETONE_NOT_SUPPORTED_BUBBLE_TITLE);
  ;
  nudge_data.announce_chromevox = false;
  nudge_data.set_anchor_view_as_parent = true;
  AnchoredNudgeManager::Get()->Show(nudge_data);

  // AnchoredNudge announcement doesn't have a separator between the title
  // and the body. Use a custom text that includes a separator to make an
  // announcement.
  std::u16string announcement = l10n_util::GetStringFUTF16(
      IDS_ASH_VIDEO_CONFERENCE_SIDETONE_BUBBLE_ANNOUNCEMENT,
      nudge_data.title_text, nudge_data.body_text);

  if (supported) {
    GetViewAccessibility().AnnouncePolitely(announcement);
  } else {
    GetViewAccessibility().AnnounceAlert(announcement);
  }
}

void TitleView::CloseSidetoneBubble() {
  auto* nudge_manager = AnchoredNudgeManager::Get();
  if (nudge_manager) {
    nudge_manager->Cancel(kSidetoneNudgeId);
  }
}

TitleView::~TitleView() {
  auto* controller = VideoConferenceTrayController::Get();
  if (controller->GetSidetoneEnabled()) {
    controller->SetSidetoneEnabled(false);
  }

  CloseSidetoneBubble();
}

BEGIN_METADATA(TitleView)
END_METADATA

}  // namespace ash::video_conference