Commit dd172713 authored by anthonyvd's avatar anthonyvd Committed by Commit bot

[WebPayments] Start populating the Payment Sheet.

This change adds the header and the Order Summary section to the
Payment Sheet in the Payment Request dialog. Both sheets still need
many tweaks and extra features but this is the first step towards the
dialog actually looking like the design specs.

Mocks here:

https://folio.googleplex.com/chrome-ux/mocks/329-future-web-pay/latest/desktop#

A screenshot of the Payment Sheet is here:

https://drive.google.com/file/d/0B-DVbqI3huZGREpIaE5yMDZjZzA/view?usp=sharing

A screenshot of the Order Summary shown when clicking the Order Summary
row is here:

https://drive.google.com/file/d/0B-DVbqI3huZGM0F0cC1sS2xLTWs/view?usp=sharing

BUG=676112

Review-Url: https://codereview.chromium.org/2592833002
Cr-Commit-Position: refs/heads/master@{#441939}
parent 80055463
......@@ -8,6 +8,7 @@
#include "base/lazy_instance.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "components/payments/payment_details_validation.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
......@@ -61,7 +62,14 @@ void PaymentRequestImpl::Init(
payments::mojom::PaymentDetailsPtr details,
payments::mojom::PaymentOptionsPtr options) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::string error;
if (!payments::validatePaymentDetails(details, &error)) {
LOG(ERROR) << error;
OnError();
return;
}
client_ = std::move(client);
details_ = std::move(details);
}
void PaymentRequestImpl::Show() {
......
......@@ -34,6 +34,7 @@ class PaymentRequestImpl : payments::mojom::PaymentRequest,
void Cancel();
void OnError();
payments::mojom::PaymentDetails* details() { return details_.get(); }
content::WebContents* web_contents() { return web_contents_; }
......@@ -44,6 +45,7 @@ class PaymentRequestImpl : payments::mojom::PaymentRequest,
content::WebContents* web_contents_;
mojo::Binding<payments::mojom::PaymentRequest> binding_;
payments::mojom::PaymentRequestClientPtr client_;
payments::mojom::PaymentDetailsPtr details_;
DISALLOW_COPY_AND_ASSIGN(PaymentRequestImpl);
};
......
......@@ -10,22 +10,16 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/payments/payment_request_impl.h"
#include "chrome/browser/ui/views/payments/payment_request_dialog.h"
#include "chrome/browser/ui/views/payments/payment_request_views_util.h"
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
namespace {
// The tag for the button that navigates back to the payment sheet.
constexpr int kBackButtonTag = 0;
} // namespace
namespace payments {
OrderSummaryViewController::OrderSummaryViewController(
......@@ -40,26 +34,37 @@ std::unique_ptr<views::View> OrderSummaryViewController::CreateView() {
views::GridLayout* layout = new views::GridLayout(content_view.get());
content_view->SetLayoutManager(layout);
views::ColumnSet* columns = layout->AddColumnSet(0);
columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
views::LabelButton* back_button =
views::MdTextButton::CreateSecondaryUiBlueButton(
this, base::ASCIIToUTF16("Back"));
back_button->set_tag(kBackButtonTag);
layout->AddView(back_button);
layout->AddView(new views::Label(
l10n_util::GetStringFUTF16(
IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_TOTAL_FORMAT,
base::ASCIIToUTF16(impl()->details()->total->label),
base::ASCIIToUTF16(impl()->details()->total->amount->value),
base::ASCIIToUTF16(impl()->details()->total->amount->currency))));
return payments::CreatePaymentView(
l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_ORDER_SUMMARY_TITLE),
CreateSheetHeaderView(
true,
l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_ORDER_SUMMARY_TITLE),
this),
std::move(content_view));
}
void OrderSummaryViewController::ButtonPressed(
views::Button* sender, const ui::Event& event) {
DCHECK_EQ(kBackButtonTag, sender->tag());
dialog()->GoBack();
switch (sender->tag()) {
case static_cast<int>(PaymentRequestCommonTags::CLOSE_BUTTON_TAG):
dialog()->CloseDialog();
break;
case static_cast<int>(PaymentRequestCommonTags::BACK_BUTTON_TAG):
dialog()->GoBack();
break;
default:
NOTREACHED();
}
}
} // namespace payments
......@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/vector_icon_button_delegate.h"
namespace payments {
......@@ -17,7 +17,7 @@ class PaymentRequestDialog;
// The PaymentRequestSheetController subtype for the Order Summary screen of the
// Payment Request flow.
class OrderSummaryViewController : public PaymentRequestSheetController,
public views::ButtonListener {
public views::VectorIconButtonDelegate {
public:
// Does not take ownership of the arguments, which should outlive this object.
OrderSummaryViewController(PaymentRequestImpl* impl,
......@@ -28,7 +28,7 @@ class OrderSummaryViewController : public PaymentRequestSheetController,
std::unique_ptr<views::View> CreateView() override;
private:
// views::ButtonListener:
// views::VectorIconButtonDelegate:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
DISALLOW_COPY_AND_ASSIGN(OrderSummaryViewController);
......
......@@ -17,6 +17,16 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/layout/fill_layout.h"
namespace chrome {
void ShowPaymentRequestDialog(payments::PaymentRequestImpl* impl) {
constrained_window::ShowWebModalDialogViews(
new payments::PaymentRequestDialog(impl), impl->web_contents());
}
} // namespace chrome
namespace payments {
namespace {
// This function creates an instance of a PaymentRequestSheetController
......@@ -37,17 +47,6 @@ std::unique_ptr<views::View> CreateViewAndInstallController(
} // namespace
namespace chrome {
void ShowPaymentRequestDialog(payments::PaymentRequestImpl* impl) {
constrained_window::ShowWebModalDialogViews(
new payments::PaymentRequestDialog(impl), impl->web_contents());
}
} // namespace chrome
namespace payments {
PaymentRequestDialog::PaymentRequestDialog(PaymentRequestImpl* impl)
: impl_(impl) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -71,6 +70,23 @@ bool PaymentRequestDialog::Cancel() {
return true;
}
bool PaymentRequestDialog::ShouldShowCloseButton() const {
// Don't show the normal close button on the dialog. This is because the
// typical dialog header doesn't allow displaying anything other that the
// title and the close button. This is insufficient for the PaymentRequest
// dialog, which must sometimes show the back arrow next to the title.
// Moreover, the title (and back arrow) should animate with the view they're
// attached to.
return false;
}
int PaymentRequestDialog::GetDialogButtons() const {
// The buttons should animate along with the different dialog sheets since
// each sheet presents a different set of buttons. Because of this, hide the
// usual dialog buttons.
return ui::DIALOG_BUTTON_NONE;
}
void PaymentRequestDialog::GoBack() {
view_stack_.Pop();
}
......@@ -82,6 +98,10 @@ void PaymentRequestDialog::ShowOrderSummary() {
true);
}
void PaymentRequestDialog::CloseDialog() {
GetWidget()->Close();
}
void PaymentRequestDialog::ShowInitialPaymentSheet() {
view_stack_.Push(
CreateViewAndInstallController<PaymentSheetViewController>(
......
......@@ -36,9 +36,12 @@ class PaymentRequestDialog : public views::DialogDelegateView {
// views::DialogDelegate
bool Cancel() override;
bool ShouldShowCloseButton() const override;
int GetDialogButtons() const override;
void GoBack();
void ShowOrderSummary();
void CloseDialog();
private:
void ShowInitialPaymentSheet();
......
......@@ -5,16 +5,66 @@
#include "chrome/browser/ui/views/payments/payment_request_views_util.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/vector_icons_public.h"
#include "ui/views/background.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/vector_icon_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
namespace payments {
std::unique_ptr<views::View> CreateSheetHeaderView(
bool show_back_arrow,
const base::string16& title,
views::VectorIconButtonDelegate* delegate) {
std::unique_ptr<views::View> container = base::MakeUnique<views::View>();
views::GridLayout* layout = new views::GridLayout(container.get());
container->SetLayoutManager(layout);
views::ColumnSet* columns = layout->AddColumnSet(0);
// A column for the optional back arrow.
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
// A column for the title.
columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
1, views::GridLayout::USE_PREF, 0, 0);
// A column for the close button.
columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
if (!show_back_arrow) {
layout->SkipColumns(1);
} else {
views::VectorIconButton* back_arrow = new views::VectorIconButton(delegate);
back_arrow->SetIcon(gfx::VectorIconId::NAVIGATE_BACK);
back_arrow->SetSize(back_arrow->GetPreferredSize());
back_arrow->set_tag(static_cast<int>(
PaymentRequestCommonTags::BACK_BUTTON_TAG));
layout->AddView(back_arrow);
}
views::Label* title_label = new views::Label(title);
title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
layout->AddView(title_label);
views::Button* close_button =
views::BubbleFrameView::CreateCloseButton(delegate);
close_button->set_tag(static_cast<int>(
PaymentRequestCommonTags::CLOSE_BUTTON_TAG));
layout->AddView(close_button);
return container;
}
std::unique_ptr<views::View> CreatePaymentView(
const base::string16& title, std::unique_ptr<views::View> content_view) {
std::unique_ptr<views::View> header_view,
std::unique_ptr<views::View> content_view) {
std::unique_ptr<views::View> view = base::MakeUnique<views::View>();
view->set_background(views::Background::CreateSolidBackground(SK_ColorWHITE));
......@@ -24,12 +74,19 @@ std::unique_ptr<views::View> CreatePaymentView(
views::GridLayout* layout = new views::GridLayout(view.get());
view->SetLayoutManager(layout);
constexpr int kTopInsetSize = 9;
constexpr int kBottomInsetSize = 18;
constexpr int kSideInsetSize = 14;
layout->SetInsets(
kTopInsetSize, kSideInsetSize, kBottomInsetSize, kSideInsetSize);
views::ColumnSet* columns = layout->AddColumnSet(0);
columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
1, views::GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
layout->AddView(new views::Label(title));
// |header_view| will be deleted when |view| is.
layout->AddView(header_view.release());
layout->StartRow(0, 0);
// |content_view| will be deleted when |view| is.
......
......@@ -10,17 +10,49 @@
#include "base/strings/string16.h"
namespace views {
class VectorIconButtonDelegate;
class View;
}
namespace payments {
// Creates a view to be displayed in the PaymentRequestDialog. |title| is the
// text displayed on top of the dialog and |content_view| is displayed between
// the title and the pay/cancel buttons. The returned view takes ownership of
// |content_view|.
enum class PaymentRequestCommonTags {
BACK_BUTTON_TAG = 0,
CLOSE_BUTTON_TAG,
// This is the max value of tags for controls common to multiple
// PaymentRequest contexts. Individual screens that handle both common and
// specific events with tags can start their specific tags at this value.
PAYMENT_REQUEST_COMMON_TAG_MAX
};
// Creates and returns a header for all the sheets in the PaymentRequest dialog.
// The header contains an optional back arrow button (if |show_back_arrow| is
// true), a |title| label, and a right-aligned X close button. |delegate|
// becomes the delegate for the back and close buttons.
// +---------------------------+
// | <- | Title | X |
// +---------------------------+
std::unique_ptr<views::View> CreateSheetHeaderView(
bool show_back_arrow,
const base::string16& title,
views::VectorIconButtonDelegate* delegate);
// Creates a view to be displayed in the PaymentRequestDialog.
// |header_view| is the view displayed on top of the dialog, containing title,
// (optional) back button, and close buttons.
// |content_view| is displayed between |header_view| and the pay/cancel buttons.
// The returned view takes ownership of |header_view| and |content_view|.
// +---------------------------+
// | HEADER VIEW |
// +---------------------------+
// | CONTENT |
// | VIEW |
// +---------------------------+
// | | CANCEL | PAY |
// +---------------------------+
std::unique_ptr<views::View> CreatePaymentView(
const base::string16& title, std::unique_ptr<views::View> content_view);
std::unique_ptr<views::View> header_view,
std::unique_ptr<views::View> content_view);
} // namespace payments
......
......@@ -9,24 +9,110 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/payments/payment_request_impl.h"
#include "chrome/browser/ui/views/payments/payment_request_dialog.h"
#include "chrome/browser/ui/views/payments/payment_request_views_util.h"
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/font.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/vector_icons_public.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/button/label_button.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/styled_label.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
namespace payments {
namespace {
// The tag for the button that navigates to the Order Summary sheet.
constexpr int kOrderSummaryTag = 0;
enum class PaymentSheetViewControllerTags {
// The tag for the button that navigates to the Order Summary sheet.
SHOW_ORDER_SUMMARY_BUTTON = static_cast<int>(
payments::PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX),
};
// Creates a clickable row to be displayed in the Payment Sheet. It contains
// a section name and some content, followed by a chevron as a clickability
// affordance. Both, either, or none of |content_view| and |extra_content_view|
// may be present, the difference between the two being that content is pinned
// to the left and extra_content is pinned to the right.
// The row also displays a light gray horizontal ruler on its lower boundary.
// +----------------------------+
// | Name | Content | Extra | > |
// +~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ <-- ruler
class PaymentSheetRow : public views::CustomButton {
public:
PaymentSheetRow(views::ButtonListener* listener,
const base::string16& section_name,
std::unique_ptr<views::View> content_view,
std::unique_ptr<views::View> extra_content_view)
: views::CustomButton(listener) {
SetBorder(views::CreateSolidSidedBorder(0, 0, 1, 0, SK_ColorLTGRAY));
views::GridLayout* layout = new views::GridLayout(this);
constexpr int kRowVerticalInset = 18;
// The rows have extra inset compared to the header so that their right edge
// lines up with the close button's X rather than its invisible right edge.
constexpr int kRowExtraRightInset = 8;
layout->SetInsets(
kRowVerticalInset, 0, kRowVerticalInset, kRowExtraRightInset);
SetLayoutManager(layout);
views::ColumnSet* columns = layout->AddColumnSet(0);
// A column for the section name.
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
// A column for the content.
columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
1, views::GridLayout::USE_PREF, 0, 0);
// A column for the extra content.
columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
constexpr int kPaddingColumnsWidth = 25;
columns->AddPaddingColumn(0, kPaddingColumnsWidth);
// A column for the chevron.
columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
views::Label* name_label = new views::Label(section_name);
layout->AddView(name_label);
if (content_view) {
layout->AddView(content_view.release());
} else {
layout->SkipColumns(1);
}
if (extra_content_view) {
layout->AddView(extra_content_view.release());
} else {
layout->SkipColumns(1);
}
views::ImageView* chevron = new views::ImageView();
chevron->SetImage(gfx::CreateVectorIcon(
gfx::VectorIconId::SUBMENU_ARROW,
color_utils::DeriveDefaultIconColor(name_label->enabled_color())));
layout->AddView(chevron);
}
DISALLOW_COPY_AND_ASSIGN(PaymentSheetRow);
};
} // namespace
namespace payments {
PaymentSheetViewController::PaymentSheetViewController(
PaymentRequestImpl* impl, PaymentRequestDialog* dialog)
: PaymentRequestSheetController(impl, dialog) {}
......@@ -39,26 +125,57 @@ std::unique_ptr<views::View> PaymentSheetViewController::CreateView() {
views::GridLayout* layout = new views::GridLayout(content_view.get());
content_view->SetLayoutManager(layout);
views::ColumnSet* columns = layout->AddColumnSet(0);
columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
1, views::GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
views::LabelButton* order_summary_button =
views::MdTextButton::CreateSecondaryUiBlueButton(
this, base::ASCIIToUTF16("Order Summary"));
order_summary_button->set_tag(kOrderSummaryTag);
layout->AddView(order_summary_button);
return payments::CreatePaymentView(
l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_PAYMENT_SHEET_TITLE),
layout->AddView(CreatePaymentSheetSummaryRow().release());
return CreatePaymentView(
CreateSheetHeaderView(
false,
l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_PAYMENT_SHEET_TITLE),
this),
std::move(content_view));
}
void PaymentSheetViewController::ButtonPressed(
views::Button* sender, const ui::Event& event) {
DCHECK_EQ(kOrderSummaryTag, sender->tag());
switch (sender->tag()) {
case static_cast<int>(PaymentRequestCommonTags::CLOSE_BUTTON_TAG):
dialog()->CloseDialog();
break;
case static_cast<int>(
PaymentSheetViewControllerTags::SHOW_ORDER_SUMMARY_BUTTON):
dialog()->ShowOrderSummary();
break;
default:
NOTREACHED();
}
}
std::unique_ptr<views::View>
PaymentSheetViewController::CreateOrderSummarySectionContent() {
base::string16 label_value =
l10n_util::GetStringFUTF16(
IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_TOTAL_FORMAT,
base::ASCIIToUTF16(impl()->details()->total->label),
base::ASCIIToUTF16(impl()->details()->total->amount->currency),
base::ASCIIToUTF16(impl()->details()->total->amount->value));
return base::MakeUnique<views::Label>(label_value);
}
dialog()->ShowOrderSummary();
std::unique_ptr<views::Button>
PaymentSheetViewController::CreatePaymentSheetSummaryRow() {
std::unique_ptr<views::Button> section = base::MakeUnique<PaymentSheetRow>(
this,
l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_NAME),
std::unique_ptr<views::View>(nullptr),
CreateOrderSummarySectionContent());
section->set_tag(static_cast<int>(
PaymentSheetViewControllerTags::SHOW_ORDER_SUMMARY_BUTTON));
return section;
}
} // namespace payments
......@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/vector_icon_button_delegate.h"
namespace payments {
......@@ -17,7 +17,7 @@ class PaymentRequestDialog;
// The PaymentRequestSheetController subtype for the Payment Sheet screen of the
// Payment Request dialog.
class PaymentSheetViewController : public PaymentRequestSheetController,
public views::ButtonListener {
public views::VectorIconButtonDelegate {
public:
// Does not take ownership of the arguments, which should outlive this object.
PaymentSheetViewController(PaymentRequestImpl* impl,
......@@ -28,9 +28,12 @@ class PaymentSheetViewController : public PaymentRequestSheetController,
std::unique_ptr<views::View> CreateView() override;
private:
// views::ButtonListener:
// views::VectorIconButtonDelegate:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
std::unique_ptr<views::View> CreateOrderSummarySectionContent();
std::unique_ptr<views::Button> CreatePaymentSheetSummaryRow();
DISALLOW_COPY_AND_ASSIGN(PaymentSheetViewController);
};
......
......@@ -162,14 +162,14 @@
<if expr="_google_chrome">
<message name="IDS_AUTOFILL_CREDIT_CARD_OPTIONS_POPUP" desc="The label of the text displayed in the Autofill Credit Card popup to direct the user to the Autofill settings UI.">
Chrome Autofill settings...
Chrome Autofill settings...
</message>
</if>
<if expr="not _google_chrome">
<message name="IDS_AUTOFILL_CREDIT_CARD_OPTIONS_POPUP" desc="The label of the text displayed in the Autofill Credit Card popup to direct the user to the Autofill settings UI.">
<message name="IDS_AUTOFILL_CREDIT_CARD_OPTIONS_POPUP" desc="The label of the text displayed in the Autofill Credit Card popup to direct the user to the Autofill settings UI.">
Chromium Autofill settings...
</message>
</if>
</if>
<message name="IDS_AUTOFILL_OPTIONS_CONTENT_DESCRIPTION" desc="The text verbalised by a screen reader for the button that directs the user to the Autofill settings UI. This string is not displayed.">
settings
......@@ -347,4 +347,11 @@
CVC
</message>
<!-- Payment Request -->
<message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_NAME" desc="The name of the Order Summary section in the Payment Sheet of the Payment Request dialog.">
Order summary
</message>
<message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_TOTAL_FORMAT" desc="The format specifier of the Total label in the Order Summary section of the Payment Sheet of the Payment Request dialog.">
<ph name="TOTAL_LABEL">$1<ex>Total</ex></ph> <ph name="CURRENCY_CODE">$2<ex>USD</ex></ph> <ph name="FORMATTED_TOTAL_AMOUNT">$3<ex>$ 12.34</ex></ph>
</message>
</grit-part>
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