blob: 9dba66381e48c4c1441d8e218b7bcc6913aa20c2 [file] [log] [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.
#include "chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.h"
#include <string>
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/autofill/autofill_bubble_base.h"
#include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
#include "chrome/browser/ui/autofill/payments/save_iban_ui.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/page_action/page_action_icon_type.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill {
// static
IbanBubbleController* IbanBubbleController::GetOrCreate(
content::WebContents* web_contents) {
if (!web_contents) {
return nullptr;
}
IbanBubbleControllerImpl::CreateForWebContents(web_contents);
return IbanBubbleControllerImpl::FromWebContents(web_contents);
}
IbanBubbleControllerImpl::~IbanBubbleControllerImpl() = default;
void IbanBubbleControllerImpl::OfferLocalSave(
const IBAN& iban,
bool should_show_prompt,
AutofillClient::LocalSaveIBANPromptCallback save_iban_prompt_callback) {
// Don't show the bubble if it's already visible.
if (bubble_view()) {
return;
}
iban_ = iban;
is_reshow_ = false;
local_save_iban_prompt_callback_ = std::move(save_iban_prompt_callback);
current_bubble_type_ = IbanBubbleType::kLocalSave;
if (should_show_prompt) {
// Local save callback should not be null for kLocalSave state.
DCHECK(!local_save_iban_prompt_callback_.is_null());
Show();
} else {
ShowIconOnly();
}
}
void IbanBubbleControllerImpl::ReshowBubble() {
// Don't show the bubble if it's already visible.
if (bubble_view()) {
return;
}
is_reshow_ = true;
DCHECK(current_bubble_type_ != IbanBubbleType::kInactive);
// Local save callback should not be null for kLocalSave state.
DCHECK(!local_save_iban_prompt_callback_.is_null() ||
current_bubble_type_ != IbanBubbleType::kLocalSave);
Show();
}
std::u16string IbanBubbleControllerImpl::GetWindowTitle() const {
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
return l10n_util::GetStringUTF16(
IDS_AUTOFILL_SAVE_IBAN_PROMPT_TITLE_LOCAL);
case IbanBubbleType::kManageSavedIban:
return l10n_util::GetStringUTF16(IDS_AUTOFILL_IBAN_SAVED);
case IbanBubbleType::kInactive:
NOTREACHED();
return std::u16string();
}
}
std::u16string IbanBubbleControllerImpl::GetAcceptButtonText() const {
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
return l10n_util::GetStringUTF16(
IDS_AUTOFILL_SAVE_IBAN_BUBBLE_LOCAL_SAVE_ACCEPT);
case IbanBubbleType::kManageSavedIban:
return l10n_util::GetStringUTF16(IDS_AUTOFILL_DONE);
case IbanBubbleType::kInactive:
NOTREACHED();
return std::u16string();
}
}
std::u16string IbanBubbleControllerImpl::GetDeclineButtonText() const {
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
return l10n_util::GetStringUTF16(
IDS_AUTOFILL_SAVE_IBAN_BUBBLE_LOCAL_SAVE_NO_THANKS);
case IbanBubbleType::kManageSavedIban:
case IbanBubbleType::kInactive:
NOTREACHED();
return std::u16string();
}
}
const IBAN& IbanBubbleControllerImpl::GetIBAN() const {
return iban_;
}
void IbanBubbleControllerImpl::OnAcceptButton(const std::u16string& nickname) {
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
DCHECK(!local_save_iban_prompt_callback_.is_null());
// Show an animated IBAN saved confirmation message next time
// UpdatePageActionIcon() is called.
should_show_iban_saved_label_animation_ = true;
autofill_metrics::LogSaveIbanBubbleResultSavedWithNicknameMetric(
!nickname.empty());
iban_.set_nickname(nickname);
std::move(local_save_iban_prompt_callback_)
.Run(AutofillClient::SaveIBANOfferUserDecision::kAccepted, nickname);
return;
case IbanBubbleType::kManageSavedIban:
return;
case IbanBubbleType::kInactive:
NOTREACHED();
}
}
void IbanBubbleControllerImpl::OnCancelButton() {
if (current_bubble_type_ == IbanBubbleType::kLocalSave) {
std::move(local_save_iban_prompt_callback_)
.Run(AutofillClient::SaveIBANOfferUserDecision::kDeclined,
absl::nullopt);
}
}
void IbanBubbleControllerImpl::OnManageSavedIbanExtraButtonClicked() {
DCHECK(current_bubble_type_ == IbanBubbleType::kManageSavedIban);
chrome::ShowSettingsSubPage(
chrome::FindBrowserWithWebContents(web_contents()),
chrome::kPaymentsSubPage);
OnBubbleClosed(PaymentsBubbleClosedReason::kClosed);
}
void IbanBubbleControllerImpl::OnBubbleClosed(
PaymentsBubbleClosedReason closed_reason) {
set_bubble_view(nullptr);
// Log save IBAN prompt result according to the closed reason.
if (current_bubble_type_ == IbanBubbleType::kLocalSave) {
autofill_metrics::SaveIbanBubbleResult metric;
switch (closed_reason) {
case PaymentsBubbleClosedReason::kAccepted:
metric = autofill_metrics::SaveIbanBubbleResult::kAccepted;
break;
case PaymentsBubbleClosedReason::kCancelled:
metric = autofill_metrics::SaveIbanBubbleResult::kCancelled;
break;
case PaymentsBubbleClosedReason::kClosed:
metric = autofill_metrics::SaveIbanBubbleResult::kClosed;
break;
case PaymentsBubbleClosedReason::kNotInteracted:
metric = autofill_metrics::SaveIbanBubbleResult::kNotInteracted;
break;
case PaymentsBubbleClosedReason::kLostFocus:
metric = autofill_metrics::SaveIbanBubbleResult::kLostFocus;
break;
case PaymentsBubbleClosedReason::kUnknown:
metric = autofill_metrics::SaveIbanBubbleResult::kUnknown;
NOTREACHED();
break;
}
autofill_metrics::LogSaveIbanBubbleResultMetric(metric, is_reshow_);
}
// Handles `current_bubble_type_` change according to its current type and the
// `closed_reason`.
if (closed_reason == PaymentsBubbleClosedReason::kAccepted) {
if (current_bubble_type_ == IbanBubbleType::kLocalSave) {
current_bubble_type_ = IbanBubbleType::kManageSavedIban;
} else {
current_bubble_type_ = IbanBubbleType::kInactive;
}
} else if (closed_reason == PaymentsBubbleClosedReason::kCancelled) {
current_bubble_type_ = IbanBubbleType::kInactive;
}
UpdatePageActionIcon();
}
IbanBubbleControllerImpl::IbanBubbleControllerImpl(
content::WebContents* web_contents)
: AutofillBubbleControllerBase(web_contents),
content::WebContentsUserData<IbanBubbleControllerImpl>(*web_contents),
personal_data_manager_(
PersonalDataManagerFactory::GetInstance()->GetForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()))) {
}
IbanBubbleType IbanBubbleControllerImpl::GetBubbleType() const {
return current_bubble_type_;
}
std::u16string IbanBubbleControllerImpl::GetSavePaymentIconTooltipText() const {
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
case IbanBubbleType::kManageSavedIban:
return l10n_util::GetStringUTF16(IDS_TOOLTIP_SAVE_IBAN);
case IbanBubbleType::kInactive:
return std::u16string();
}
}
bool IbanBubbleControllerImpl::ShouldShowSavingPaymentAnimation() const {
return false;
}
bool IbanBubbleControllerImpl::ShouldShowPaymentSavedLabelAnimation() const {
return should_show_iban_saved_label_animation_;
}
bool IbanBubbleControllerImpl::ShouldShowSaveFailureBadge() const {
return false;
}
void IbanBubbleControllerImpl::OnAnimationEnded() {
// Do not repeat the animation next time UpdatePageActionIcon() is called,
// unless explicitly set somewhere else.
should_show_iban_saved_label_animation_ = false;
}
bool IbanBubbleControllerImpl::IsIconVisible() const {
// If there is no bubble to show, then there should be no icon.
return current_bubble_type_ != IbanBubbleType::kInactive;
}
AutofillBubbleBase* IbanBubbleControllerImpl::GetPaymentBubbleView() const {
return bubble_view();
}
SavePaymentIconController::PaymentBubbleType
IbanBubbleControllerImpl::GetPaymentBubbleType() const {
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
return PaymentBubbleType::kSaveIban;
case IbanBubbleType::kManageSavedIban:
return PaymentBubbleType::kManageSavedIban;
case IbanBubbleType::kInactive:
return PaymentBubbleType::kUnknown;
}
}
PageActionIconType IbanBubbleControllerImpl::GetPageActionIconType() {
return PageActionIconType::kSaveIban;
}
void IbanBubbleControllerImpl::DoShowBubble() {
Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
AutofillBubbleHandler* autofill_bubble_handler =
browser->window()->GetAutofillBubbleHandler();
set_bubble_view(autofill_bubble_handler->ShowIbanBubble(
web_contents(), this, /*is_user_gesture=*/is_reshow_,
current_bubble_type_));
DCHECK(bubble_view());
DCHECK(current_bubble_type_ != IbanBubbleType::kInactive);
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
autofill_metrics::LogSaveIbanBubbleOfferMetric(
autofill_metrics::SaveIbanPromptOffer::kShown, is_reshow_);
break;
case IbanBubbleType::kManageSavedIban:
// TODO(crbug.com/1349109): Add metrics for manage saved IBAN mode.
break;
case IbanBubbleType::kInactive:
NOTREACHED();
}
if (observer_for_testing_) {
observer_for_testing_->OnBubbleShown();
}
}
void IbanBubbleControllerImpl::ShowIconOnly() {
DCHECK(current_bubble_type_ != IbanBubbleType::kInactive);
// Local save callback should not be null for LOCAL_SAVE state.
DCHECK(!local_save_iban_prompt_callback_.is_null() ||
current_bubble_type_ != IbanBubbleType::kLocalSave);
DCHECK(!bubble_view());
// Show the icon only. The bubble can still be displayed if the user
// explicitly clicks the icon.
UpdatePageActionIcon();
switch (current_bubble_type_) {
case IbanBubbleType::kLocalSave:
autofill_metrics::LogSaveIbanBubbleOfferMetric(
autofill_metrics::SaveIbanPromptOffer::kNotShownMaxStrikesReached,
is_reshow_);
break;
case IbanBubbleType::kManageSavedIban:
break;
case IbanBubbleType::kInactive:
NOTREACHED();
}
if (observer_for_testing_) {
observer_for_testing_->OnIconShown();
}
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(IbanBubbleControllerImpl);
} // namespace autofill