// 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 "chrome/browser/ui/chromeos/magic_boost/magic_boost_card_controller.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "chrome/browser/ui/chromeos/magic_boost/magic_boost_constants.h"
#include "chrome/browser/ui/chromeos/magic_boost/magic_boost_metrics.h"
#include "chrome/browser/ui/chromeos/magic_boost/magic_boost_opt_in_card.h"
#include "chromeos/components/magic_boost/public/cpp/magic_boost_state.h"
#include "chromeos/crosapi/mojom/magic_boost.mojom.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/unique_widget_ptr.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/check_deref.h"
#include "chrome/browser/ash/crosapi/crosapi_ash.h"
#include "chrome/browser/ash/crosapi/crosapi_manager.h"
#include "chrome/browser/ash/magic_boost/magic_boost_controller_ash.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/lacros/lacros_service.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#endif
namespace chromeos {
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
crosapi::mojom::MagicBoostController* g_crosapi_instance_for_testing = nullptr;
crosapi::mojom::MagicBoostController& GetMagicBoostControllerAsh() {
if (g_crosapi_instance_for_testing) {
return CHECK_DEREF(g_crosapi_instance_for_testing);
}
return CHECK_DEREF(crosapi::CrosapiManager::Get()
->crosapi_ash()
->magic_boost_controller_ash());
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace
MagicBoostCardController::MagicBoostCardController() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Bind remote and pass receiver to `MagicBoostController`.
chromeos::LacrosService::Get()->BindMagicBoostController(
remote_.BindNewPipeAndPassReceiver());
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
MagicBoostCardController::~MagicBoostCardController() = default;
void MagicBoostCardController::OnContextMenuShown(Profile* profile) {}
void MagicBoostCardController::OnTextAvailable(
const gfx::Rect& anchor_bounds,
const std::string& selected_text,
const std::string& surrounding_text) {
ShowOptInUi(/*anchor_view_bounds=*/anchor_bounds);
}
void MagicBoostCardController::OnAnchorBoundsChanged(
const gfx::Rect& anchor_bounds) {
if (!opt_in_widget_ || !opt_in_widget_->GetContentsView()) {
return;
}
views::AsViewClass<MagicBoostOptInCard>(opt_in_widget_->GetContentsView())
->UpdateWidgetBounds(/*anchor_view_bounds=*/anchor_bounds);
}
void MagicBoostCardController::OnDismiss(bool is_other_command_executed) {
// If context menu is dismissed and the opt-in widget is active (i.e. keyboard
// focus is on a button), we should not close the widget.
if (opt_in_widget_ && !opt_in_widget_->IsActive()) {
opt_in_widget_.reset();
}
}
void MagicBoostCardController::ShowOptInUi(
const gfx::Rect& anchor_view_bounds) {
CHECK(!opt_in_widget_);
// If the disclaimer view is showing, close it.
CloseDisclaimerUi();
opt_in_widget_ = MagicBoostOptInCard::CreateWidget(
/*controller=*/this, anchor_view_bounds);
opt_in_widget_->ShowInactive();
magic_boost::RecordOptInCardActionMetrics(
opt_in_features_, magic_boost::OptInCardAction::kShowCard);
}
void MagicBoostCardController::CloseOptInUi() {
opt_in_widget_.reset();
}
void MagicBoostCardController::ShowDisclaimerUi(int64_t display_id) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
remote_->ShowDisclaimerUi(display_id, transition_action_, opt_in_features_);
#else // BUILDFLAG(IS_CHROMEOS_ASH)
GetMagicBoostControllerAsh().ShowDisclaimerUi(display_id, transition_action_,
opt_in_features_);
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
}
void MagicBoostCardController::CloseDisclaimerUi() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
remote_->CloseDisclaimerUi();
#else // BUILDFLAG(IS_CHROMEOS_ASH)
GetMagicBoostControllerAsh().CloseDisclaimerUi();
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
}
void MagicBoostCardController::SetOptInFeature(const OptInFeatures& features) {
opt_in_features_ = features;
}
const OptInFeatures& MagicBoostCardController::GetOptInFeatures() const {
return opt_in_features_;
}
base::WeakPtr<MagicBoostCardController> MagicBoostCardController::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void MagicBoostCardController::BindMagicBoostControllerCrosapiForTesting(
mojo::PendingRemote<crosapi::mojom::MagicBoostController> pending_remote) {
remote_.reset();
remote_.Bind(std::move(pending_remote));
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
#if BUILDFLAG(IS_CHROMEOS_ASH)
void MagicBoostCardController::SetMagicBoostControllerCrosapiForTesting(
crosapi::mojom::MagicBoostController* delegate) {
g_crosapi_instance_for_testing = delegate;
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace chromeos