Commit 35d6e5bb authored by siyua's avatar siyua Committed by Commit Bot

Adding Legal Message to Migration Dialogs

1) Added legal message (clickable) to the offer dialog.

2) Added a Close Button which will be shown when the
user clicks save button and the migration process lasts for more than
5 secs.

3) Modified ChromeAutofillClient to enable passing legal message
to the LocalCardMigrationDialogControllerImpl.

4) Adjusted format/style of the dialog contents according to the mock:
go/autofill-paradise.

5) Added an experiment flag (disabled by default) to control whether we want to show migration
feedback to the user.

Bug: 852904
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: Ic0ca348fc689486a21d53a76921ee5954cb08295
Reviewed-on: https://chromium-review.googlesource.com/1192688
Commit-Queue: Siyu An <siyua@chromium.org>
Reviewed-by: default avatarMathieu Perreault <mathp@chromium.org>
Reviewed-by: default avatarBret Sepulveda <bsep@chromium.org>
Reviewed-by: default avatarFabio Tirelo <ftirelo@chromium.org>
Reviewed-by: default avatarTao Bai <michaelbai@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#587886}
parent d977bcbb
......@@ -268,6 +268,7 @@ void AwAutofillClient::ShowLocalCardMigrationDialog(
}
void AwAutofillClient::ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<autofill::MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) {
NOTIMPLEMENTED();
......
......@@ -76,6 +76,7 @@ class AwAutofillClient : public autofill::AutofillClient,
void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) override;
void ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<autofill::MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) override;
void ConfirmSaveAutofillProfile(const autofill::AutofillProfile& profile,
......
......@@ -217,6 +217,7 @@ void ChromeAutofillClient::ShowLocalCardMigrationDialog(
}
void ChromeAutofillClient::ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) {
#if !defined(OS_ANDROID)
......@@ -228,6 +229,7 @@ void ChromeAutofillClient::ConfirmMigrateLocalCardToCloud(
controller->SetViewState(LocalCardMigrationDialogState::kOffered);
controller->SetCardList(migratable_credit_cards);
controller->ShowDialog(
std::move(legal_message),
CreateLocalCardMigrationDialogView(controller, web_contents()),
std::move(start_migrating_cards_closure));
#endif
......
......@@ -66,6 +66,7 @@ class ChromeAutofillClient
void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) override;
void ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) override;
void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
......
......@@ -36,11 +36,18 @@ LocalCardMigrationDialogControllerImpl::
}
void LocalCardMigrationDialogControllerImpl::ShowDialog(
std::unique_ptr<base::DictionaryValue> legal_message,
LocalCardMigrationDialog* local_card_migration_dialog,
base::OnceClosure user_accepted_migration_closure) {
if (local_card_migration_dialog_)
local_card_migration_dialog_->CloseDialog();
if (!LegalMessageLine::Parse(*legal_message, &legal_message_lines_,
/*escape_apostrophes=*/true)) {
// TODO(crbug/867194): Add metric.
return;
}
local_card_migration_dialog_ = local_card_migration_dialog;
local_card_migration_dialog_->ShowDialog(
std::move(user_accepted_migration_closure));
......@@ -66,6 +73,11 @@ void LocalCardMigrationDialogControllerImpl::SetCardList(
migratable_credit_cards_ = migratable_credit_cards;
}
const LegalMessageLines&
LocalCardMigrationDialogControllerImpl::GetLegalMessageLines() const {
return legal_message_lines_;
}
void LocalCardMigrationDialogControllerImpl::OnCardSelected(int index) {
migratable_credit_cards_[index].ToggleChosen();
}
......
......@@ -25,7 +25,8 @@ class LocalCardMigrationDialogControllerImpl
public:
~LocalCardMigrationDialogControllerImpl() override;
void ShowDialog(LocalCardMigrationDialog* local_card_migration_Dialog,
void ShowDialog(std::unique_ptr<base::DictionaryValue> legal_message,
LocalCardMigrationDialog* local_card_migration_Dialog,
base::OnceClosure user_accepted_migration_closure_);
// LocalCardMigrationDialogController:
......@@ -33,6 +34,7 @@ class LocalCardMigrationDialogControllerImpl
void SetViewState(LocalCardMigrationDialogState view_state) override;
const std::vector<MigratableCreditCard>& GetCardList() const override;
void SetCardList(std::vector<MigratableCreditCard>& card_list) override;
const LegalMessageLines& GetLegalMessageLines() const override;
void OnCardSelected(int index) override;
void OnDialogClosed() override;
......@@ -48,6 +50,8 @@ class LocalCardMigrationDialogControllerImpl
LocalCardMigrationDialogState view_state_;
LegalMessageLines legal_message_lines_;
// TODO(crbug.com/867194): Currently we will not handle the case of local
// cards added/deleted during migration. migratable_credit_cards_ are local
// cards presented when the user accepts the intermediate bubble.
......
......@@ -26,6 +26,7 @@ enum DialogViewId : int {
OK_BUTTON, // Can say [Save], [Next], [Confirm],
// or [Done] depending on context
CANCEL_BUTTON, // Typically says [No thanks]
CLOSE_BUTTON, // Typically says [Close]
MANAGE_CARDS_BUTTON, // Typicall says [Manage cards]
// The following are views::Link objects (clickable).
......
......@@ -6,6 +6,7 @@
#include "base/location.h"
#include "base/macros.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/autofill/local_card_migration_dialog_factory.h"
#include "chrome/browser/ui/autofill/local_card_migration_dialog_state.h"
......@@ -15,9 +16,11 @@
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/chrome_typography.h"
#include "chrome/common/url_constants.h"
#include "components/autofill/core/browser/legal_message_line.h"
#include "components/autofill/core/browser/local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/payments_service_url.h"
#include "components/autofill/core/browser/ui/local_card_migration_dialog_controller.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/grit/components_scaled_resources.h"
#include "components/strings/grit/components_strings.h"
......@@ -35,11 +38,13 @@
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/separator.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/throbber.h"
#include "ui/views/layout/box_layout.h"
......@@ -79,14 +84,14 @@ void LocalCardMigrationDialogView::CloseDialog() {
}
void LocalCardMigrationDialogView::OnMigrationFinished() {
show_close_button_timer_.Stop();
title_->SetText(GetDialogTitle());
explanation_text_->SetText(GetDialogInstruction());
for (int index = 0; index < card_list_view_->child_count(); index++) {
AsMigratableCardView(card_list_view_->child_at(index))
->UpdateCardView(controller_->GetViewState());
}
delete separator_;
separator_ = nullptr;
separator_->SetVisible(false);
// TODO(crbug/867194): Add tip value prompt.
SetMigrationIsPending(false);
}
......@@ -108,6 +113,14 @@ void LocalCardMigrationDialogView::AddedToWidget() {
GetWidget()->AddObserver(this);
}
views::View* LocalCardMigrationDialogView::CreateExtraView() {
close_migration_dialog_button_.reset(
views::MdTextButton::CreateSecondaryUiButton(
this, l10n_util::GetStringUTF16(IDS_CLOSE)));
close_migration_dialog_button_->SetVisible(false);
return close_migration_dialog_button_.get();
}
bool LocalCardMigrationDialogView::ShouldShowCloseButton() const {
return false;
}
......@@ -128,8 +141,8 @@ bool LocalCardMigrationDialogView::Accept() {
switch (controller_->GetViewState()) {
case LocalCardMigrationDialogState::kOffered:
OnSaveButtonClicked();
// Dialog will not be closed if it is the migration offer dialog.
return false;
return !base::FeatureList::IsEnabled(
features::kAutofillLocalCardMigrationShowFeedback);
case LocalCardMigrationDialogState::kFinished:
case LocalCardMigrationDialogState::kActionRequired:
return true;
......@@ -153,10 +166,28 @@ void LocalCardMigrationDialogView::OnWidgetClosing(views::Widget* widget) {
widget->RemoveObserver(this);
}
// TODO(crbug/867194): Add button pressed for kDeleteCardButtonTag
// TODO(crbug/867194): Add button pressed logic for kDeleteCardButtonTag.
void LocalCardMigrationDialogView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
// If button clicked is the |close_migration_dialog_button_|, close the
// dialog.
if (sender == close_migration_dialog_button_.get()) {
CloseDialog();
} else {
// Checkbox is clicked.
controller_->OnCardSelected(sender->tag());
}
}
// TODO(crbug/867194): Add metrics for legal message link clicking.
void LocalCardMigrationDialogView::StyledLabelLinkClicked(
views::StyledLabel* label,
const gfx::Range& range,
int event_flags) {
if (!controller_)
return;
legal_message_container_->OnLinkClicked(label, range, web_contents_);
}
void LocalCardMigrationDialogView::Init() {
......@@ -167,36 +198,47 @@ void LocalCardMigrationDialogView::Init() {
SetLayoutManager(std::make_unique<views::FillLayout>());
// Set up main contents container.
views::View* main_container = new views::View();
std::unique_ptr<views::View> main_container = std::make_unique<views::View>();
constexpr int kMigrationDialogUnrelatedControlVerticalDistance = 24;
main_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(),
provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
AddChildView(main_container);
views::ImageView* image = new views::ImageView();
kMigrationDialogUnrelatedControlVerticalDistance));
std::unique_ptr<views::View> image_container =
std::make_unique<views::View>();
image_container->SetLayoutManager(
std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
constexpr int kMigrationDialogImageBorderBottom = 16;
image_container->SetBorder(
views::CreateEmptyBorder(0, 0, kMigrationDialogImageBorderBottom, 0));
std::unique_ptr<views::ImageView> image =
std::make_unique<views::ImageView>();
image->SetImage(rb.GetImageSkiaNamed(GetHeaderImageId()));
main_container->AddChildView(image);
image_container->AddChildView(image.release());
main_container->AddChildView(image_container.release());
title_ = std::make_unique<views::Label>(GetDialogTitle(),
views::style::CONTEXT_DIALOG_TITLE);
main_container->AddChildView(title_.get());
content_container_ = new views::View();
content_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
std::unique_ptr<views::View> contents_container =
std::make_unique<views::View>();
contents_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(),
provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
content_container_->SetBorder(views::CreateEmptyBorder(
provider->GetDialogInsetsForContentType(views::TEXT, views::CONTROL)));
main_container->AddChildView(content_container_);
constexpr int kMigrationDialogInsets = 24;
gfx::Insets migration_dialog_insets = gfx::Insets(kMigrationDialogInsets);
contents_container->SetBorder(
views::CreateEmptyBorder(migration_dialog_insets));
title_ =
new views::Label(GetDialogTitle(), views::style::CONTEXT_DIALOG_TITLE);
content_container_->AddChildView(title_);
explanation_text_ =
new views::Label(GetDialogInstruction(), CONTEXT_BODY_TEXT_LARGE,
explanation_text_ = std::make_unique<views::Label>(
GetDialogInstruction(), CONTEXT_BODY_TEXT_LARGE,
ChromeTextStyle::STYLE_SECONDARY);
explanation_text_->SetMultiLine(true);
explanation_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
content_container_->AddChildView(explanation_text_);
contents_container->AddChildView(explanation_text_.get());
card_list_view_ = new views::View();
card_list_view_ = std::make_unique<views::View>();
const std::vector<MigratableCreditCard>& migratable_credit_cards =
controller_->GetCardList();
views::BoxLayout* card_list_view_layout_ =
......@@ -207,21 +249,35 @@ void LocalCardMigrationDialogView::Init() {
card_list_view_layout_->set_main_axis_alignment(
views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
for (size_t index = 0; index < migratable_credit_cards.size(); index++) {
card_list_view_->AddChildView(new MigratableCardView(
migratable_credit_cards[index], this, static_cast<int>(index)));
card_list_view_->AddChildView(
std::make_unique<MigratableCardView>(migratable_credit_cards[index],
this, static_cast<int>(index))
.release());
}
views::ScrollView* card_list_scroll_bar = new views::ScrollView();
std::unique_ptr<views::ScrollView> card_list_scroll_bar =
std::make_unique<views::ScrollView>();
card_list_scroll_bar->set_hide_horizontal_scrollbar(true);
card_list_scroll_bar->SetContents(card_list_view_);
card_list_scroll_bar->SetContents(card_list_view_.get());
card_list_scroll_bar->set_draw_overflow_indicator(false);
constexpr int kCardListScrollViewHeight = 140;
card_list_scroll_bar->ClipHeightTo(0, kCardListScrollViewHeight);
content_container_->AddChildView(card_list_scroll_bar);
separator_ = new views::Separator();
main_container->AddChildView(separator_);
// TODO(crbug/867194): Add legal message.
contents_container->AddChildView(card_list_scroll_bar.release());
main_container->AddChildView(contents_container.release());
separator_ = std::make_unique<views::Separator>();
main_container->AddChildView(separator_.get());
legal_message_container_ = std::make_unique<LegalMessageView>(
controller_->GetLegalMessageLines(), this);
constexpr int kMigrationDialogContentMarginBottomText = 48;
legal_message_container_->SetBorder(
views::CreateEmptyBorder(0, migration_dialog_insets.left(),
kMigrationDialogContentMarginBottomText,
migration_dialog_insets.right()));
main_container->AddChildView(legal_message_container_.get());
AddChildView(main_container.release());
}
base::string16 LocalCardMigrationDialogView::GetDialogTitle() const {
......@@ -290,6 +346,9 @@ void LocalCardMigrationDialogView::OnSaveButtonClicked() {
}
SetMigrationIsPending(true);
std::move(user_accepted_migration_closure_).Run();
show_close_button_timer_.Start(
FROM_HERE, features::GetTimeoutForMigrationPromptFeedbackCloseButton(),
this, &LocalCardMigrationDialogView::ShowCloseButton);
}
void LocalCardMigrationDialogView::OnCancelButtonClicked() {
......@@ -298,13 +357,10 @@ void LocalCardMigrationDialogView::OnCancelButtonClicked() {
void LocalCardMigrationDialogView::OnViewCardsButtonClicked() {
constexpr int kPaymentsProfileUserIndex = 0;
OpenUrl(payments::GetManageInstrumentsUrl(kPaymentsProfileUserIndex));
}
void LocalCardMigrationDialogView::OpenUrl(const GURL& url) {
web_contents_->OpenURL(content::OpenURLParams(
url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated*/ false));
payments::GetManageInstrumentsUrl(kPaymentsProfileUserIndex),
content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false));
}
void LocalCardMigrationDialogView::SetMigrationIsPending(
......@@ -314,6 +370,10 @@ void LocalCardMigrationDialogView::SetMigrationIsPending(
GetDialogClientView()->Layout();
}
void LocalCardMigrationDialogView::ShowCloseButton() {
close_migration_dialog_button_->SetVisible(true);
}
LocalCardMigrationDialog* CreateLocalCardMigrationDialogView(
LocalCardMigrationDialogController* controller,
content::WebContents* web_contents) {
......
......@@ -6,8 +6,12 @@
#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_VIEW_H_
#include "base/macros.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/autofill/local_card_migration_dialog.h"
#include "chrome/browser/ui/views/autofill/dialog_view_ids.h"
#include "chrome/browser/ui/views/autofill/view_util.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/styled_label_listener.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_delegate.h"
......@@ -28,6 +32,7 @@ class MigratableCardView;
class LocalCardMigrationDialogView : public LocalCardMigrationDialog,
public views::ButtonListener,
public views::StyledLabelListener,
public views::DialogDelegateView,
public views::WidgetObserver {
public:
......@@ -44,6 +49,7 @@ class LocalCardMigrationDialogView : public LocalCardMigrationDialog,
gfx::Size CalculatePreferredSize() const override;
ui::ModalType GetModalType() const override;
void AddedToWidget() override;
views::View* CreateExtraView() override;
bool ShouldShowCloseButton() const override;
base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
bool IsDialogButtonEnabled(ui::DialogButton button) const override;
......@@ -56,6 +62,11 @@ class LocalCardMigrationDialogView : public LocalCardMigrationDialog,
// views::ButtonListener
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// views::StyledLabelListener:
void StyledLabelLinkClicked(views::StyledLabel* label,
const gfx::Range& range,
int event_flags) override;
private:
void Init();
base::string16 GetDialogTitle() const;
......@@ -66,25 +77,33 @@ class LocalCardMigrationDialogView : public LocalCardMigrationDialog,
void OnSaveButtonClicked();
void OnCancelButtonClicked();
void OnViewCardsButtonClicked();
void OpenUrl(const GURL& url);
void SetMigrationIsPending(bool is_pending);
void ShowCloseButton();
LocalCardMigrationDialogController* controller_;
content::WebContents* web_contents_;
// Contains title, explanation and card scroll bar view.
views::View* content_container_ = nullptr;
views::Label* title_ = nullptr;
std::unique_ptr<views::Label> title_;
views::Label* explanation_text_ = nullptr;
std::unique_ptr<views::Label> explanation_text_;
// A list of MigratableCardView.
views::View* card_list_view_ = nullptr;
std::unique_ptr<views::View> card_list_view_;
// Separates the card scroll bar view and the legal message.
views::Separator* separator_ = nullptr;
std::unique_ptr<views::Separator> separator_;
// The button displays "Close". If clicked, will close the dialog
// in pending state.
std::unique_ptr<views::View> close_migration_dialog_button_;
// Timer that will call ShowCloseButton() after the migration process
// has started and is pending for acertain amount of time which can be
// configured through Finch.
base::OneShotTimer show_close_button_timer_;
std::unique_ptr<LegalMessageView> legal_message_container_;
// Whether the uploading is in progress and results are
// pending.
......
......@@ -71,10 +71,13 @@ void MigratableCardView::Init(
views::BoxLayout::kHorizontal, gfx::Insets(),
provider->GetDistanceMetric(DISTANCE_RELATED_CONTROL_HORIZONTAL_SMALL)));
checkbox_ = new views::Checkbox(base::string16());
checkbox_ = new views::Checkbox(base::string16(), listener);
checkbox_->SetChecked(migratable_credit_card.is_chosen());
checkbox_->set_tag(card_index);
checkbox_->SetVisible(true);
// TODO(crbug/867194): Currently the ink drop animation circle is cut by the
// border of scroll bar view. Find a way to adjust the format.
checkbox_->SetInkDropMode(views::InkDropHostView::InkDropMode::OFF);
AddChildView(checkbox_);
constexpr int kMigrationResultImageSize = 16;
......@@ -107,7 +110,8 @@ void MigratableCardView::Init(
std::unique_ptr<views::Label> card_expiration =
std::make_unique<views::Label>(migratable_credit_card.credit_card()
.AbbreviatedExpirationDateForDisplay(),
views::style::CONTEXT_LABEL);
views::style::CONTEXT_LABEL,
ChromeTextStyle::STYLE_SECONDARY);
AddChildView(card_expiration.release());
delete_card_from_local_button_ = views::CreateVectorImageButton(listener);
......
......@@ -41,23 +41,7 @@
namespace autofill {
namespace {
const int kTooltipIconSize = 12;
std::unique_ptr<views::StyledLabel> CreateLegalMessageLineLabel(
const LegalMessageLine& line,
views::StyledLabelListener* listener) {
std::unique_ptr<views::StyledLabel> label(
new views::StyledLabel(line.text(), listener));
label->SetTextContext(CONTEXT_BODY_TEXT_LARGE);
label->SetDefaultTextStyle(ChromeTextStyle::STYLE_SECONDARY);
for (const LegalMessageLine::Link& link : line.links()) {
label->AddStyleRange(link.range,
views::StyledLabel::RangeStyleInfo::CreateForLink());
}
return label;
}
} // namespace
SaveCardOfferBubbleViews::SaveCardOfferBubbleViews(
......@@ -65,25 +49,17 @@ SaveCardOfferBubbleViews::SaveCardOfferBubbleViews(
const gfx::Point& anchor_point,
content::WebContents* web_contents,
SaveCardBubbleController* controller)
: SaveCardBubbleViews(anchor_view, anchor_point, web_contents, controller) {
}
: SaveCardBubbleViews(anchor_view, anchor_point, web_contents, controller),
web_contents_(web_contents) {}
views::View* SaveCardOfferBubbleViews::CreateFootnoteView() {
if (controller()->GetLegalMessageLines().empty())
return nullptr;
// Use BoxLayout to provide insets around the label.
views::View* footnote_view_ = new View();
footnote_view_->SetLayoutManager(
std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
footnote_view_ =
new LegalMessageView(controller()->GetLegalMessageLines(), this);
footnote_view_->set_id(DialogViewId::FOOTNOTE_VIEW);
// Add a StyledLabel for each line of the legal message.
for (const LegalMessageLine& line : controller()->GetLegalMessageLines()) {
footnote_view_->AddChildView(
CreateLegalMessageLineLabel(line, this).release());
}
SetFootnoteViewForTesting(footnote_view_);
return footnote_view_;
}
......@@ -125,25 +101,7 @@ void SaveCardOfferBubbleViews::StyledLabelLinkClicked(views::StyledLabel* label,
if (!controller())
return;
// Index of |label| within its parent's view hierarchy is the same as the
// legal message line index. DCHECK this assumption to guard against future
// layout changes.
DCHECK_EQ(static_cast<size_t>(label->parent()->child_count()),
controller()->GetLegalMessageLines().size());
const auto& links =
controller()
->GetLegalMessageLines()[label->parent()->GetIndexOf(label)]
.links();
for (const LegalMessageLine::Link& link : links) {
if (link.range == range) {
controller()->OnLegalMessageLinkClicked(link.url);
return;
}
}
// |range| was not found.
NOTREACHED();
footnote_view_->OnLinkClicked(label, range, web_contents_);
}
void SaveCardOfferBubbleViews::ContentsChanged(
......
......@@ -7,6 +7,7 @@
#include "chrome/browser/ui/views/autofill/save_card_bubble_views.h"
#include "chrome/browser/ui/views/autofill/view_util.h"
#include "ui/views/controls/styled_label_listener.h"
#include "ui/views/controls/textfield/textfield_controller.h"
......@@ -50,8 +51,12 @@ class SaveCardOfferBubbleViews : public SaveCardBubbleViews,
~SaveCardOfferBubbleViews() override;
content::WebContents* web_contents_;
views::Textfield* cardholder_name_textfield_ = nullptr;
LegalMessageView* footnote_view_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(SaveCardOfferBubbleViews);
};
......
......@@ -8,6 +8,7 @@
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/chrome_typography.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
......@@ -20,7 +21,9 @@
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/separator.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/style/typography.h"
......@@ -96,6 +99,8 @@ TitleWithIconAndSeparatorView::TitleWithIconAndSeparatorView(
/*right=*/separator_horizontal_padding));
}
TitleWithIconAndSeparatorView::~TitleWithIconAndSeparatorView() {}
gfx::Size TitleWithIconAndSeparatorView::GetMinimumSize() const {
// View::GetMinumumSize() defaults to GridLayout::GetPreferredSize(), but that
// gives a larger frame width, so the dialog will become wider than it should.
......@@ -112,4 +117,55 @@ views::Textfield* CreateCvcTextfield() {
return textfield;
}
LegalMessageView::LegalMessageView(const LegalMessageLines& legal_message_lines,
views::StyledLabelListener* listener)
: legal_message_lines_(legal_message_lines) {
SetLayoutManager(
std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
for (const LegalMessageLine& line : legal_message_lines) {
AddChildView(CreateLegalMessageLineLabel(line, listener).release());
}
}
LegalMessageView::~LegalMessageView() {}
std::unique_ptr<views::StyledLabel>
LegalMessageView::CreateLegalMessageLineLabel(
const LegalMessageLine& line,
views::StyledLabelListener* listener) {
std::unique_ptr<views::StyledLabel> label(
new views::StyledLabel(line.text(), listener));
label->SetTextContext(CONTEXT_BODY_TEXT_LARGE);
label->SetDefaultTextStyle(ChromeTextStyle::STYLE_SECONDARY);
for (const LegalMessageLine::Link& link : line.links()) {
label->AddStyleRange(link.range,
views::StyledLabel::RangeStyleInfo::CreateForLink());
}
return label;
}
void LegalMessageView::OnLinkClicked(views::StyledLabel* label,
const gfx::Range& range,
content::WebContents* web_contents) {
// Index of |label| within its parent's view hierarchy is the same as the
// legal message line index. DCHECK this assumption to guard against future
// layout changes.
DCHECK_EQ(static_cast<size_t>(label->parent()->child_count()),
legal_message_lines_.size());
const std::vector<LegalMessageLine::Link>& links =
legal_message_lines_[label->parent()->GetIndexOf(label)].links();
for (const LegalMessageLine::Link& link : links) {
if (link.range == range) {
web_contents->OpenURL(content::OpenURLParams(
link.url, content::Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
/*is_renderer_initiated=*/false));
return;
}
}
// |range| was not found.
NOTREACHED();
}
} // namespace autofill
......@@ -6,9 +6,13 @@
#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_VIEW_UTIL_H_
#include "base/strings/string16.h"
#include "components/autofill/core/browser/legal_message_line.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/controls/styled_label_listener.h"
#include "ui/views/view.h"
namespace views {
class StyledLabel;
class Textfield;
} // namespace views
......@@ -20,7 +24,7 @@ namespace autofill {
class TitleWithIconAndSeparatorView : public views::View {
public:
explicit TitleWithIconAndSeparatorView(const base::string16& window_title);
~TitleWithIconAndSeparatorView() override = default;
~TitleWithIconAndSeparatorView() override;
private:
// views::View:
......@@ -30,6 +34,26 @@ class TitleWithIconAndSeparatorView : public views::View {
// Creates and returns a small Textfield intended to be used for CVC entry.
views::Textfield* CreateCvcTextfield();
// Defines a view with legal message. This class handles the legal message
// parsing and the links clicking events.
class LegalMessageView : public views::View {
public:
explicit LegalMessageView(const LegalMessageLines& legal_message_lines,
views::StyledLabelListener* listener);
~LegalMessageView() override;
void OnLinkClicked(views::StyledLabel* label,
const gfx::Range& range,
content::WebContents* web_contents);
private:
std::unique_ptr<views::StyledLabel> CreateLegalMessageLineLabel(
const LegalMessageLine& line,
views::StyledLabelListener* listener);
LegalMessageLines legal_message_lines_;
};
} // namespace autofill
#endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_VIEW_UTIL_H_
......@@ -144,9 +144,11 @@ class AutofillClient : public RiskDataLoader {
virtual void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) = 0;
// Runs |closure| if the user would like the selected
// |migratable_credit_cards| to be uploaded to cloud.
// Shows a dialog with the given |legal_message|. Runs |closure| if
// the user would like the selected |migratable_credit_cards| to be
// uploaded to cloud.
virtual void ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) = 0;
......
......@@ -208,7 +208,7 @@ void LocalCardMigrationManager::ShowMainMigrationDialog() {
user_accepted_main_migration_dialog_ = false;
// Pops up a larger, modal dialog showing the local cards to be uploaded.
client_->ConfirmMigrateLocalCardToCloud(
migratable_credit_cards_,
std::move(legal_message_), migratable_credit_cards_,
base::BindOnce(
&LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog,
weak_ptr_factory_.GetWeakPtr()));
......
......@@ -77,6 +77,7 @@ void TestAutofillClient::ShowLocalCardMigrationDialog(
}
void TestAutofillClient::ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) {
std::move(start_migrating_cards_closure).Run();
......
......@@ -45,6 +45,7 @@ class TestAutofillClient : public AutofillClient {
void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) override;
void ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) override;
void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
......
......@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/autofill/core/browser/legal_message_line.h"
namespace autofill {
......@@ -30,6 +31,7 @@ class LocalCardMigrationDialogController {
// TODO(crbug.com/867194): Ensure this would not be called when migration is
// happending.
virtual void SetCardList(std::vector<MigratableCreditCard>& card_list) = 0;
virtual const LegalMessageLines& GetLegalMessageLines() const = 0;
virtual void OnCardSelected(int index) = 0;
virtual void OnDialogClosed() = 0;
......
......@@ -102,6 +102,11 @@ const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{
const base::Feature kAutofillExpandedPopupViews{
"AutofillExpandedPopupViews", base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether Autofill Local Card Migration will show result dialogs.
const base::Feature kAutofillLocalCardMigrationShowFeedback{
"AutofillLocalCardMigrationShowFeedback",
base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether the manual fill fallback will be present.
const base::Feature kAutofillManualFallback{"AutofillManualFallback",
base::FEATURE_DISABLED_BY_DEFAULT};
......@@ -258,6 +263,9 @@ const base::Feature kAutomaticPasswordGeneration = {
const base::Feature kSingleClickAutofill{"SingleClickAutofill",
base::FEATURE_ENABLED_BY_DEFAULT};
const char kAutofillLocalCardMigrationCloseButtonDelay[] =
"show_close_migration_dialog_button_delay";
const char kAutofillCreditCardLocalCardMigrationParameterName[] = "variant";
const char kAutofillCreditCardLocalCardMigrationParameterWithoutSettingsPage[] =
......@@ -293,6 +301,14 @@ LocalCardMigrationExperimentalFlag GetLocalCardMigrationExperimentalFlag() {
return LocalCardMigrationExperimentalFlag::kMigrationIncludeSettingsPage;
}
base::TimeDelta GetTimeoutForMigrationPromptFeedbackCloseButton() {
constexpr int show_close_button_timeout_in_seconds = 5;
return base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
kAutofillCreditCardLocalCardMigration,
kAutofillLocalCardMigrationCloseButtonDelay,
show_close_button_timeout_in_seconds));
}
bool IsAutofillUpstreamAlwaysRequestCardholderNameExperimentEnabled() {
return base::FeatureList::IsEnabled(
features::kAutofillUpstreamAlwaysRequestCardholderName);
......
......@@ -39,6 +39,7 @@ extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload;
extern const base::Feature kAutofillExpandedPopupViews;
extern const base::Feature kAutofillLocalCardMigrationShowFeedback;
extern const base::Feature kAutofillManualFallback;
extern const base::Feature kAutofillPreferServerNamePredictions;
extern const base::Feature kAutofillNoLocalSaveOnUploadSuccess;
......@@ -76,6 +77,7 @@ extern const base::Feature kAutomaticPasswordGeneration;
extern const base::Feature kSingleClickAutofill;
extern const base::Feature kAutofillCreditCardLocalCardMigration;
extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[];
extern const char kAutofillLocalCardMigrationCloseButtonDelay[];
extern const char kAutofillCreditCardLocalCardMigrationParameterName[];
extern const char kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey[];
extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
......@@ -106,6 +108,10 @@ enum class LocalCardMigrationExperimentalFlag {
// settings page migration.
LocalCardMigrationExperimentalFlag GetLocalCardMigrationExperimentalFlag();
// Returns the time delay for the local card migration dialog to show the close
// button.
base::TimeDelta GetTimeoutForMigrationPromptFeedbackCloseButton();
// For testing purposes; not to be launched. When enabled, Chrome Upstream
// always requests that the user enters/confirms cardholder name in the
// offer-to-save dialog, regardless of if it was present or if the user is a
......
......@@ -59,6 +59,7 @@ class ChromeAutofillClientIOS : public AutofillClient {
void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) override;
void ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) override;
void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
......
......@@ -176,6 +176,7 @@ void ChromeAutofillClientIOS::ShowLocalCardMigrationDialog(
}
void ChromeAutofillClientIOS::ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) {
NOTIMPLEMENTED();
......
......@@ -52,6 +52,7 @@ class WebViewAutofillClientIOS : public AutofillClient {
void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) override;
void ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) override;
void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
......
......@@ -97,6 +97,7 @@ void WebViewAutofillClientIOS::ShowLocalCardMigrationDialog(
}
void WebViewAutofillClientIOS::ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message,
std::vector<MigratableCreditCard>& migratable_credit_cards,
base::OnceClosure start_migrating_cards_closure) {
NOTIMPLEMENTED();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment