Commit 9fb7181f authored by mahmadi's avatar mahmadi Committed by Commit bot

Selected shipping option in payment summary view + shipping option selection view

BUG=602666

Review-Url: https://codereview.chromium.org/2621453002
Cr-Commit-Position: refs/heads/master@{#443226}
parent 2555903a
...@@ -963,6 +963,9 @@ Handoff must also be enabled in the General section of Settings, and your device ...@@ -963,6 +963,9 @@ Handoff must also be enabled in the General section of Settings, and your device
<message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE" desc="Title of the view that allows the user to select the shipping address for satisfying a payment request [iOS only]."> <message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE" desc="Title of the view that allows the user to select the shipping address for satisfying a payment request [iOS only].">
Shipping Address Shipping Address
</message> </message>
<message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE" desc="Title of the view that allows the user to select the shipping option for satisfying a payment request [iOS only].">
Shipping Method
</message>
<message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_ADD_BUTTON" desc="Label of the button to add a new shipping address [iOS only]."> <message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_ADD_BUTTON" desc="Label of the button to add a new shipping address [iOS only].">
Add Address... Add Address...
</message> </message>
......
...@@ -36,6 +36,10 @@ source_set("payments") { ...@@ -36,6 +36,10 @@ source_set("payments") {
"shipping_address_selection_coordinator.mm", "shipping_address_selection_coordinator.mm",
"shipping_address_selection_view_controller.h", "shipping_address_selection_view_controller.h",
"shipping_address_selection_view_controller.mm", "shipping_address_selection_view_controller.mm",
"shipping_option_selection_coordinator.h",
"shipping_option_selection_coordinator.mm",
"shipping_option_selection_view_controller.h",
"shipping_option_selection_view_controller.mm",
] ]
deps = [ deps = [
":injected_js", ":injected_js",
...@@ -67,6 +71,8 @@ source_set("unit_tests") { ...@@ -67,6 +71,8 @@ source_set("unit_tests") {
"payment_items_display_view_controller_unittest.mm", "payment_items_display_view_controller_unittest.mm",
"shipping_address_selection_coordinator_unittest.mm", "shipping_address_selection_coordinator_unittest.mm",
"shipping_address_selection_view_controller_unittest.mm", "shipping_address_selection_view_controller_unittest.mm",
"shipping_option_selection_coordinator_unittest.mm",
"shipping_option_selection_view_controller_unittest.mm",
] ]
deps = [ deps = [
":payments", ":payments",
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/credit_card.h"
#import "ios/chrome/browser/payments/payment_request_utils.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
#import "ios/chrome/browser/ui/collection_view/collection_view_model.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
...@@ -17,7 +18,6 @@ ...@@ -17,7 +18,6 @@
#include "ios/chrome/browser/ui/rtl_geometry.h" #include "ios/chrome/browser/ui/rtl_geometry.h"
#include "ios/chrome/grit/ios_strings.h" #include "ios/chrome/grit/ios_strings.h"
#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h" #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
...@@ -137,10 +137,6 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -137,10 +137,6 @@ typedef NS_ENUM(NSInteger, ItemType) {
CollectionViewModel* model = self.collectionViewModel; CollectionViewModel* model = self.collectionViewModel;
[model addSectionWithIdentifier:SectionIdentifierPayment]; [model addSectionWithIdentifier:SectionIdentifierPayment];
NSNumberFormatter* currencyFormatter =
[[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// Add the total entry. // Add the total entry.
CollectionViewDetailItem* totalItem = [[[CollectionViewDetailItem alloc] CollectionViewDetailItem* totalItem = [[[CollectionViewDetailItem alloc]
initWithType:ItemTypePaymentItemTotal] autorelease]; initWithType:ItemTypePaymentItemTotal] autorelease];
...@@ -149,8 +145,8 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -149,8 +145,8 @@ typedef NS_ENUM(NSInteger, ItemType) {
NSString* currencyCode = base::SysUTF16ToNSString(_total.amount.currency); NSString* currencyCode = base::SysUTF16ToNSString(_total.amount.currency);
NSDecimalNumber* value = [NSDecimalNumber NSDecimalNumber* value = [NSDecimalNumber
decimalNumberWithString:SysUTF16ToNSString(_total.amount.value)]; decimalNumberWithString:SysUTF16ToNSString(_total.amount.value)];
[currencyFormatter setCurrencyCode:currencyCode]; totalItem.detailText =
totalItem.detailText = [currencyFormatter stringFromNumber:value]; payment_request_utils::FormattedCurrencyString(value, currencyCode);
[model addItem:totalItem toSectionWithIdentifier:SectionIdentifierPayment]; [model addItem:totalItem toSectionWithIdentifier:SectionIdentifierPayment];
...@@ -166,9 +162,8 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -166,9 +162,8 @@ typedef NS_ENUM(NSInteger, ItemType) {
base::SysUTF16ToNSString(paymentItem.amount.currency); base::SysUTF16ToNSString(paymentItem.amount.currency);
NSDecimalNumber* value = [NSDecimalNumber NSDecimalNumber* value = [NSDecimalNumber
decimalNumberWithString:SysUTF16ToNSString(paymentItem.amount.value)]; decimalNumberWithString:SysUTF16ToNSString(paymentItem.amount.value)];
[currencyFormatter setCurrencyCode:currencyCode]; paymentItemItem.detailText =
paymentItemItem.detailText = [currencyFormatter stringFromNumber:value]; payment_request_utils::FormattedCurrencyString(value, currencyCode);
[model addItem:paymentItemItem [model addItem:paymentItemItem
toSectionWithIdentifier:SectionIdentifierPayment]; toSectionWithIdentifier:SectionIdentifierPayment];
} }
......
...@@ -19,9 +19,13 @@ class CreditCard; ...@@ -19,9 +19,13 @@ class CreditCard;
@protocol PaymentMethodSelectionCoordinatorDelegate<NSObject> @protocol PaymentMethodSelectionCoordinatorDelegate<NSObject>
// Notifies the delegate that the user has selected a payment method.
- (void)paymentMethodSelectionCoordinator: - (void)paymentMethodSelectionCoordinator:
(PaymentMethodSelectionCoordinator*)coordinator (PaymentMethodSelectionCoordinator*)coordinator
selectedPaymentMethod:(autofill::CreditCard*)paymentMethod; selectedPaymentMethod:(autofill::CreditCard*)paymentMethod;
// Notifies the delegate that the user has chosen to return to the previous
// screen without making a selection.
- (void)paymentMethodSelectionCoordinatorDidReturn: - (void)paymentMethodSelectionCoordinatorDidReturn:
(PaymentMethodSelectionCoordinator*)coordinator; (PaymentMethodSelectionCoordinator*)coordinator;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#import "ios/chrome/browser/payments/payment_method_selection_coordinator.h" #import "ios/chrome/browser/payments/payment_method_selection_coordinator.h"
#import "ios/chrome/browser/payments/payment_request_view_controller.h" #import "ios/chrome/browser/payments/payment_request_view_controller.h"
#import "ios/chrome/browser/payments/shipping_address_selection_coordinator.h" #import "ios/chrome/browser/payments/shipping_address_selection_coordinator.h"
#import "ios/chrome/browser/payments/shipping_option_selection_coordinator.h"
#include "ios/web/public/payments/payment_request.h" #include "ios/web/public/payments/payment_request.h"
namespace autofill { namespace autofill {
...@@ -34,7 +35,8 @@ class PersonalDataManager; ...@@ -34,7 +35,8 @@ class PersonalDataManager;
: ChromeCoordinator<PaymentRequestViewControllerDelegate, : ChromeCoordinator<PaymentRequestViewControllerDelegate,
PaymentItemsDisplayCoordinatorDelegate, PaymentItemsDisplayCoordinatorDelegate,
PaymentMethodSelectionCoordinatorDelegate, PaymentMethodSelectionCoordinatorDelegate,
ShippingAddressSelectionCoordinatorDelegate> ShippingAddressSelectionCoordinatorDelegate,
ShippingOptionSelectionCoordinatorDelegate>
// Creates a Payment Request coordinator that will present UI on // Creates a Payment Request coordinator that will present UI on
// |viewController| using data available from |personalDataManager|. // |viewController| using data available from |personalDataManager|.
...@@ -66,6 +68,10 @@ class PersonalDataManager; ...@@ -66,6 +68,10 @@ class PersonalDataManager;
@property(nonatomic, readonly) @property(nonatomic, readonly)
autofill::AutofillProfile* selectedShippingAddress; autofill::AutofillProfile* selectedShippingAddress;
// The currently selected shipping option, if any.
@property(nonatomic, readonly)
web::PaymentShippingOption* selectedShippingOption;
// The payment method selected by the user, if any. // The payment method selected by the user, if any.
@property(nonatomic, readonly) autofill::CreditCard* selectedPaymentMethod; @property(nonatomic, readonly) autofill::CreditCard* selectedPaymentMethod;
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
_itemsDisplayCoordinator; _itemsDisplayCoordinator;
base::scoped_nsobject<ShippingAddressSelectionCoordinator> base::scoped_nsobject<ShippingAddressSelectionCoordinator>
_shippingAddressSelectionCoordinator; _shippingAddressSelectionCoordinator;
base::scoped_nsobject<ShippingOptionSelectionCoordinator>
_shippingOptionSelectionCoordinator;
base::scoped_nsobject<PaymentMethodSelectionCoordinator> base::scoped_nsobject<PaymentMethodSelectionCoordinator>
_methodSelectionCoordinator; _methodSelectionCoordinator;
...@@ -46,6 +48,8 @@ ...@@ -46,6 +48,8 @@
@synthesize pageTitle = _pageTitle; @synthesize pageTitle = _pageTitle;
@synthesize pageHost = _pageHost; @synthesize pageHost = _pageHost;
@synthesize selectedShippingAddress = _selectedShippingAddress; @synthesize selectedShippingAddress = _selectedShippingAddress;
@synthesize selectedShippingOption = _selectedShippingOption;
@synthesize selectedPaymentMethod = _selectedPaymentMethod; @synthesize selectedPaymentMethod = _selectedPaymentMethod;
- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController - (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
...@@ -73,6 +77,16 @@ ...@@ -73,6 +77,16 @@
if (addresses.size() > 0) if (addresses.size() > 0)
_selectedShippingAddress = addresses[0]; _selectedShippingAddress = addresses[0];
for (size_t i = 0; i < _paymentRequest.details.shipping_options.size(); ++i) {
web::PaymentShippingOption* shippingOption =
&_paymentRequest.details.shipping_options[i];
if (shippingOption->selected) {
// If more than one option has |selected| set, the last one in the
// sequence should be treated as the selected item.
_selectedShippingOption = shippingOption;
}
}
const std::vector<autofill::CreditCard*> cards = [self supportedMethods]; const std::vector<autofill::CreditCard*> cards = [self supportedMethods];
if (cards.size() > 0) if (cards.size() > 0)
_selectedPaymentMethod = cards[0]; _selectedPaymentMethod = cards[0];
...@@ -83,6 +97,7 @@ ...@@ -83,6 +97,7 @@
[_viewController setPageTitle:_pageTitle]; [_viewController setPageTitle:_pageTitle];
[_viewController setPageHost:_pageHost]; [_viewController setPageHost:_pageHost];
[_viewController setSelectedShippingAddress:_selectedShippingAddress]; [_viewController setSelectedShippingAddress:_selectedShippingAddress];
[_viewController setSelectedShippingOption:_selectedShippingOption];
[_viewController setSelectedPaymentMethod:_selectedPaymentMethod]; [_viewController setSelectedPaymentMethod:_selectedPaymentMethod];
[_viewController setDelegate:self]; [_viewController setDelegate:self];
[_viewController loadModel]; [_viewController loadModel];
...@@ -100,6 +115,7 @@ ...@@ -100,6 +115,7 @@
[_navigationController dismissViewControllerAnimated:YES completion:nil]; [_navigationController dismissViewControllerAnimated:YES completion:nil];
_itemsDisplayCoordinator.reset(); _itemsDisplayCoordinator.reset();
_shippingAddressSelectionCoordinator.reset(); _shippingAddressSelectionCoordinator.reset();
_shippingOptionSelectionCoordinator.reset();
_methodSelectionCoordinator.reset(); _methodSelectionCoordinator.reset();
_navigationController.reset(); _navigationController.reset();
_viewController.reset(); _viewController.reset();
...@@ -218,6 +234,26 @@ ...@@ -218,6 +234,26 @@
[_shippingAddressSelectionCoordinator start]; [_shippingAddressSelectionCoordinator start];
} }
- (void)paymentRequestViewControllerSelectShippingOption {
_shippingOptionSelectionCoordinator.reset(
[[ShippingOptionSelectionCoordinator alloc]
initWithBaseViewController:_viewController]);
std::vector<web::PaymentShippingOption*> shippingOptions;
shippingOptions.reserve(_paymentRequest.details.shipping_options.size());
std::transform(std::begin(_paymentRequest.details.shipping_options),
std::end(_paymentRequest.details.shipping_options),
std::back_inserter(shippingOptions),
[](web::PaymentShippingOption& option) { return &option; });
[_shippingOptionSelectionCoordinator setShippingOptions:shippingOptions];
[_shippingOptionSelectionCoordinator
setSelectedShippingOption:_selectedShippingOption];
[_shippingOptionSelectionCoordinator setDelegate:self];
[_shippingOptionSelectionCoordinator start];
}
- (void)paymentRequestViewControllerSelectPaymentMethod { - (void)paymentRequestViewControllerSelectPaymentMethod {
_methodSelectionCoordinator.reset([[PaymentMethodSelectionCoordinator alloc] _methodSelectionCoordinator.reset([[PaymentMethodSelectionCoordinator alloc]
initWithBaseViewController:_viewController]); initWithBaseViewController:_viewController]);
...@@ -260,6 +296,25 @@ ...@@ -260,6 +296,25 @@
_shippingAddressSelectionCoordinator.reset(); _shippingAddressSelectionCoordinator.reset();
} }
#pragma mark - ShippingOptionSelectionCoordinatorDelegate
- (void)shippingOptionSelectionCoordinator:
(ShippingOptionSelectionCoordinator*)coordinator
selectedShippingOption:
(web::PaymentShippingOption*)shippingOption {
_selectedShippingOption = shippingOption;
[_viewController updateSelectedShippingOption:shippingOption];
[_shippingOptionSelectionCoordinator stop];
_shippingOptionSelectionCoordinator.reset();
}
- (void)shippingOptionSelectionCoordinatorDidReturn:
(ShippingAddressSelectionCoordinator*)coordinator {
[_shippingOptionSelectionCoordinator stop];
_shippingOptionSelectionCoordinator.reset();
}
#pragma mark - PaymentMethodSelectionCoordinatorDelegate #pragma mark - PaymentMethodSelectionCoordinatorDelegate
- (void)paymentMethodSelectionCoordinator: - (void)paymentMethodSelectionCoordinator:
......
...@@ -16,6 +16,11 @@ namespace payment_request_utils { ...@@ -16,6 +16,11 @@ namespace payment_request_utils {
// Helper function to get the shipping address label from an autofill profile. // Helper function to get the shipping address label from an autofill profile.
NSString* AddressLabelFromAutofillProfile(autofill::AutofillProfile* profile); NSString* AddressLabelFromAutofillProfile(autofill::AutofillProfile* profile);
// Helper function that returns a formatted currency string given the value and
// the currency code.
NSString* FormattedCurrencyString(NSDecimalNumber* value,
NSString* currencyCode);
} // namespace payment_request_utils } // namespace payment_request_utils
#endif // IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_UTILS_H_ #endif // IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_UTILS_H_
...@@ -26,4 +26,13 @@ NSString* AddressLabelFromAutofillProfile(autofill::AutofillProfile* profile) { ...@@ -26,4 +26,13 @@ NSString* AddressLabelFromAutofillProfile(autofill::AutofillProfile* profile) {
GetApplicationContext()->GetApplicationLocale())); GetApplicationContext()->GetApplicationLocale()));
} }
NSString* FormattedCurrencyString(NSDecimalNumber* value,
NSString* currencyCode) {
NSNumberFormatter* currencyFormatter =
[[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[currencyFormatter setCurrencyCode:currencyCode];
return [currencyFormatter stringFromNumber:value];
}
} // namespace payment_request_utils } // namespace payment_request_utils
...@@ -20,6 +20,7 @@ class CreditCard; ...@@ -20,6 +20,7 @@ class CreditCard;
- (void)paymentRequestViewControllerDidConfirm; - (void)paymentRequestViewControllerDidConfirm;
- (void)paymentRequestViewControllerDisplayPaymentItems; - (void)paymentRequestViewControllerDisplayPaymentItems;
- (void)paymentRequestViewControllerSelectShippingAddress; - (void)paymentRequestViewControllerSelectShippingAddress;
- (void)paymentRequestViewControllerSelectShippingOption;
- (void)paymentRequestViewControllerSelectPaymentMethod; - (void)paymentRequestViewControllerSelectPaymentMethod;
@end @end
...@@ -44,6 +45,9 @@ class CreditCard; ...@@ -44,6 +45,9 @@ class CreditCard;
// The currently selected and displayed shipping address, if any. // The currently selected and displayed shipping address, if any.
@property(nonatomic, assign) autofill::AutofillProfile* selectedShippingAddress; @property(nonatomic, assign) autofill::AutofillProfile* selectedShippingAddress;
// The currently selected and displayed shipping option, if any.
@property(nonatomic, assign) web::PaymentShippingOption* selectedShippingOption;
// The currently selected and displayed payment method, if any. // The currently selected and displayed payment method, if any.
@property(nonatomic, assign) autofill::CreditCard* selectedPaymentMethod; @property(nonatomic, assign) autofill::CreditCard* selectedPaymentMethod;
...@@ -54,6 +58,10 @@ class CreditCard; ...@@ -54,6 +58,10 @@ class CreditCard;
- (void)updateSelectedShippingAddress: - (void)updateSelectedShippingAddress:
(autofill::AutofillProfile*)shippingAddress; (autofill::AutofillProfile*)shippingAddress;
// Sets the selected shipping option and updates the UI.
- (void)updateSelectedShippingOption:
(web::PaymentShippingOption*)shippingOption;
- (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithStyle:(CollectionViewControllerStyle)style - (instancetype)initWithStyle:(CollectionViewControllerStyle)style
......
...@@ -19,16 +19,17 @@ ...@@ -19,16 +19,17 @@
#import "ios/chrome/browser/payments/cells/payment_method_item.h" #import "ios/chrome/browser/payments/cells/payment_method_item.h"
#import "ios/chrome/browser/payments/cells/shipping_address_item.h" #import "ios/chrome/browser/payments/cells/shipping_address_item.h"
#import "ios/chrome/browser/payments/payment_request_utils.h" #import "ios/chrome/browser/payments/payment_request_utils.h"
#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
#import "ios/chrome/browser/ui/collection_view/collection_view_model.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
#include "ios/chrome/browser/ui/rtl_geometry.h" #include "ios/chrome/browser/ui/rtl_geometry.h"
#include "ios/chrome/grit/ios_strings.h" #include "ios/chrome/grit/ios_strings.h"
#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h" #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h" #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
...@@ -54,6 +55,8 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -54,6 +55,8 @@ typedef NS_ENUM(NSInteger, ItemType) {
ItemTypeShippingTitle, ItemTypeShippingTitle,
ItemTypeShippingAddress, ItemTypeShippingAddress,
ItemTypeAddShippingAddress, ItemTypeAddShippingAddress,
ItemTypeShippingOption,
ItemTypeSelectShippingOption,
ItemTypePaymentTitle, ItemTypePaymentTitle,
ItemTypePaymentMethod, ItemTypePaymentMethod,
}; };
...@@ -66,6 +69,7 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -66,6 +69,7 @@ typedef NS_ENUM(NSInteger, ItemType) {
base::scoped_nsobject<MDCFlatButton> _payButton; base::scoped_nsobject<MDCFlatButton> _payButton;
ShippingAddressItem* _selectedShippingAddressItem; ShippingAddressItem* _selectedShippingAddressItem;
CollectionViewTextItem* _selectedShippingOptionItem;
base::mac::ObjCPropertyReleaser base::mac::ObjCPropertyReleaser
_propertyReleaser_PaymentRequestViewController; _propertyReleaser_PaymentRequestViewController;
...@@ -85,8 +89,9 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -85,8 +89,9 @@ typedef NS_ENUM(NSInteger, ItemType) {
@synthesize pageFavicon = _pageFavicon; @synthesize pageFavicon = _pageFavicon;
@synthesize pageTitle = _pageTitle; @synthesize pageTitle = _pageTitle;
@synthesize pageHost = _pageHost; @synthesize pageHost = _pageHost;
@synthesize selectedPaymentMethod = _selectedPaymentMethod;
@synthesize selectedShippingAddress = _selectedShippingAddress; @synthesize selectedShippingAddress = _selectedShippingAddress;
@synthesize selectedShippingOption = _selectedShippingOption;
@synthesize selectedPaymentMethod = _selectedPaymentMethod;
- (instancetype)init { - (instancetype)init {
if ((self = [super initWithStyle:CollectionViewControllerStyleAppBar])) { if ((self = [super initWithStyle:CollectionViewControllerStyleAppBar])) {
...@@ -201,11 +206,8 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -201,11 +206,8 @@ typedef NS_ENUM(NSInteger, ItemType) {
NSDecimalNumber* value = [NSDecimalNumber NSDecimalNumber* value = [NSDecimalNumber
decimalNumberWithString:SysUTF16ToNSString( decimalNumberWithString:SysUTF16ToNSString(
_paymentRequest.details.total.amount.value)]; _paymentRequest.details.total.amount.value)];
NSNumberFormatter* currencyFormatter = total.detailText =
[[[NSNumberFormatter alloc] init] autorelease]; payment_request_utils::FormattedCurrencyString(value, currencyCode);
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[currencyFormatter setCurrencyCode:currencyCode];
total.detailText = [currencyFormatter stringFromNumber:value];
if (!_paymentRequest.details.display_items.empty()) { if (!_paymentRequest.details.display_items.empty()) {
total.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator; total.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
total.accessibilityTraits |= UIAccessibilityTraitButton; total.accessibilityTraits |= UIAccessibilityTraitButton;
...@@ -221,11 +223,11 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -221,11 +223,11 @@ typedef NS_ENUM(NSInteger, ItemType) {
[model setHeader:shippingTitle [model setHeader:shippingTitle
forSectionWithIdentifier:SectionIdentifierShipping]; forSectionWithIdentifier:SectionIdentifierShipping];
CollectionViewItem* shippingItem = nil; CollectionViewItem* shippingAddressItem = nil;
if (_selectedShippingAddress) { if (_selectedShippingAddress) {
_selectedShippingAddressItem = [[[ShippingAddressItem alloc] _selectedShippingAddressItem = [[[ShippingAddressItem alloc]
initWithType:ItemTypeShippingAddress] autorelease]; initWithType:ItemTypeShippingAddress] autorelease];
shippingItem = _selectedShippingAddressItem; shippingAddressItem = _selectedShippingAddressItem;
[self fillShippingAddressItem:_selectedShippingAddressItem [self fillShippingAddressItem:_selectedShippingAddressItem
withAddress:_selectedShippingAddress]; withAddress:_selectedShippingAddress];
_selectedShippingAddressItem.accessoryType = _selectedShippingAddressItem.accessoryType =
...@@ -235,15 +237,34 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -235,15 +237,34 @@ typedef NS_ENUM(NSInteger, ItemType) {
CollectionViewDetailItem* addAddressItem = CollectionViewDetailItem* addAddressItem =
[[[CollectionViewDetailItem alloc] [[[CollectionViewDetailItem alloc]
initWithType:ItemTypeAddShippingAddress] autorelease]; initWithType:ItemTypeAddShippingAddress] autorelease];
shippingItem = addAddressItem; shippingAddressItem = addAddressItem;
addAddressItem.text = l10n_util::GetNSString( addAddressItem.text = l10n_util::GetNSString(
IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE); IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE);
addAddressItem.detailText = [l10n_util::GetNSString( addAddressItem.detailText = [l10n_util::GetNSString(
IDS_IOS_PAYMENT_REQUEST_ADD_SHIPPING_ADDRESS_BUTTON) IDS_IOS_PAYMENT_REQUEST_ADD_SHIPPING_ADDRESS_BUTTON)
uppercaseStringWithLocale:[NSLocale currentLocale]]; uppercaseStringWithLocale:[NSLocale currentLocale]];
} }
shippingItem.accessibilityTraits |= UIAccessibilityTraitButton; shippingAddressItem.accessibilityTraits |= UIAccessibilityTraitButton;
[model addItem:shippingItem [model addItem:shippingAddressItem
toSectionWithIdentifier:SectionIdentifierShipping];
CollectionViewTextItem* shippingOptionItem = nil;
if (_selectedShippingOption) {
_selectedShippingOptionItem = [[[CollectionViewTextItem alloc]
initWithType:ItemTypeShippingOption] autorelease];
shippingOptionItem = _selectedShippingOptionItem;
[self fillShippingOptionItem:_selectedShippingOptionItem
withOption:_selectedShippingOption];
} else {
shippingOptionItem = [[[CollectionViewTextItem alloc]
initWithType:ItemTypeSelectShippingOption] autorelease];
shippingOptionItem.text = l10n_util::GetNSString(
IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE);
}
shippingOptionItem.accessoryType =
MDCCollectionViewCellAccessoryDisclosureIndicator;
shippingOptionItem.accessibilityTraits |= UIAccessibilityTraitButton;
[model addItem:shippingOptionItem
toSectionWithIdentifier:SectionIdentifierShipping]; toSectionWithIdentifier:SectionIdentifierShipping];
// Payment method section. // Payment method section.
...@@ -312,6 +333,17 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -312,6 +333,17 @@ typedef NS_ENUM(NSInteger, ItemType) {
[self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]]; [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]];
} }
- (void)updateSelectedShippingOption:
(web::PaymentShippingOption*)shippingOption {
[self setSelectedShippingOption:shippingOption];
[self fillShippingOptionItem:_selectedShippingOptionItem
withOption:shippingOption];
NSIndexPath* indexPath =
[self.collectionViewModel indexPathForItem:_selectedShippingOptionItem
inSectionWithIdentifier:SectionIdentifierShipping];
[self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]];
}
#pragma mark - Helper methods #pragma mark - Helper methods
- (void)fillShippingAddressItem:(ShippingAddressItem*)item - (void)fillShippingAddressItem:(ShippingAddressItem*)item
...@@ -324,7 +356,18 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -324,7 +356,18 @@ typedef NS_ENUM(NSInteger, ItemType) {
address->GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER)); address->GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER));
} }
- (void)fillShippingOptionItem:(CollectionViewTextItem*)item
withOption:(web::PaymentShippingOption*)option {
item.text = base::SysUTF16ToNSString(option->label);
NSString* currencyCode = base::SysUTF16ToNSString(option->amount.currency);
NSDecimalNumber* value = [NSDecimalNumber
decimalNumberWithString:SysUTF16ToNSString(option->amount.value)];
item.detailText =
payment_request_utils::FormattedCurrencyString(value, currencyCode);
}
#pragma mark UICollectionViewDataSource #pragma mark UICollectionViewDataSource
- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
cellForItemAtIndexPath:(nonnull NSIndexPath*)indexPath { cellForItemAtIndexPath:(nonnull NSIndexPath*)indexPath {
UICollectionViewCell* cell = UICollectionViewCell* cell =
...@@ -336,12 +379,20 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -336,12 +379,20 @@ typedef NS_ENUM(NSInteger, ItemType) {
case ItemTypeAddShippingAddress: { case ItemTypeAddShippingAddress: {
CollectionViewDetailCell* detailCell = CollectionViewDetailCell* detailCell =
base::mac::ObjCCastStrict<CollectionViewDetailCell>(cell); base::mac::ObjCCastStrict<CollectionViewDetailCell>(cell);
detailCell.detailTextLabel.font = detailCell.detailTextLabel.font = [MDCTypography body2Font];
[[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
detailCell.detailTextLabel.textColor = detailCell.detailTextLabel.textColor =
[[MDCPalette cr_bluePalette] tint700]; [[MDCPalette cr_bluePalette] tint700];
break; break;
} }
case ItemTypeShippingOption: {
MDCCollectionViewTextCell* textCell =
base::mac::ObjCCastStrict<MDCCollectionViewTextCell>(cell);
textCell.textLabel.font = [MDCTypography body2Font];
textCell.textLabel.textColor = [[MDCPalette greyPalette] tint900];
textCell.detailTextLabel.font = [MDCTypography body1Font];
textCell.detailTextLabel.textColor = [[MDCPalette greyPalette] tint900];
break;
}
default: default:
break; break;
} }
...@@ -365,6 +416,10 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -365,6 +416,10 @@ typedef NS_ENUM(NSInteger, ItemType) {
case ItemTypeAddShippingAddress: case ItemTypeAddShippingAddress:
[_delegate paymentRequestViewControllerSelectShippingAddress]; [_delegate paymentRequestViewControllerSelectShippingAddress];
break; break;
case ItemTypeShippingOption:
case ItemTypeSelectShippingOption:
[_delegate paymentRequestViewControllerSelectShippingOption];
break;
case ItemTypePaymentMethod: case ItemTypePaymentMethod:
[_delegate paymentRequestViewControllerSelectPaymentMethod]; [_delegate paymentRequestViewControllerSelectPaymentMethod];
break; break;
...@@ -386,6 +441,8 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -386,6 +441,8 @@ typedef NS_ENUM(NSInteger, ItemType) {
return [MDCCollectionViewCell return [MDCCollectionViewCell
cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
forItem:item]; forItem:item];
} else if (type == ItemTypeShippingOption) {
return MDCCellDefaultTwoLineHeight;
} else { } else {
return MDCCellDefaultOneLineHeight; return MDCCellDefaultOneLineHeight;
} }
......
...@@ -18,10 +18,14 @@ class AutofillProfile; ...@@ -18,10 +18,14 @@ class AutofillProfile;
@protocol ShippingAddressSelectionCoordinatorDelegate<NSObject> @protocol ShippingAddressSelectionCoordinatorDelegate<NSObject>
// Notifies the delegate that the user has selected a shipping address.
- (void)shippingAddressSelectionCoordinator: - (void)shippingAddressSelectionCoordinator:
(ShippingAddressSelectionCoordinator*)coordinator (ShippingAddressSelectionCoordinator*)coordinator
selectedShippingAddress: selectedShippingAddress:
(autofill::AutofillProfile*)shippingAddress; (autofill::AutofillProfile*)shippingAddress;
// Notifies the delegate that the user has chosen to return to the previous
// screen without making a selection.
- (void)shippingAddressSelectionCoordinatorDidReturn: - (void)shippingAddressSelectionCoordinatorDidReturn:
(ShippingAddressSelectionCoordinator*)coordinator; (ShippingAddressSelectionCoordinator*)coordinator;
......
...@@ -36,4 +36,5 @@ TEST(ShippingAddressSelectionCoordinatorTest, StartAndStop) { ...@@ -36,4 +36,5 @@ TEST(ShippingAddressSelectionCoordinatorTest, StartAndStop) {
EXPECT_EQ(1u, [navigation_controller.viewControllers count]); EXPECT_EQ(1u, [navigation_controller.viewControllers count]);
} }
} }
}
} // namespace
...@@ -140,24 +140,29 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -140,24 +140,29 @@ typedef NS_ENUM(NSInteger, ItemType) {
CollectionViewModel* model = self.collectionViewModel; CollectionViewModel* model = self.collectionViewModel;
NSInteger itemType = NSInteger itemType = [model itemTypeForIndexPath:indexPath];
[self.collectionViewModel itemTypeForIndexPath:indexPath];
CollectionViewItem* item =
[self.collectionViewModel itemAtIndexPath:indexPath];
if (itemType == ItemTypeShippingAddress) { if (itemType == ItemTypeShippingAddress) {
NSInteger index = [model indexInItemTypeForIndexPath:indexPath]; NSIndexPath* currentlySelectedIndexPath = [self.collectionViewModel
DCHECK(index < (NSInteger)_shippingAddresses.size()); indexPathForItem:_selectedItem
self.selectedShippingAddress = _shippingAddresses[index]; inSectionWithIdentifier:SectionIdentifierShippingAddress];
if (currentlySelectedIndexPath != indexPath) {
ShippingAddressItem* shippingAddressItem = // Update the cells.
CollectionViewItem* item = [model itemAtIndexPath:indexPath];
ShippingAddressItem* newlySelectedItem =
base::mac::ObjCCastStrict<ShippingAddressItem>(item); base::mac::ObjCCastStrict<ShippingAddressItem>(item);
shippingAddressItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark; newlySelectedItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
_selectedItem.accessoryType = MDCCollectionViewCellAccessoryNone; _selectedItem.accessoryType = MDCCollectionViewCellAccessoryNone;
[self reconfigureCellsForItems:@[ _selectedItem, shippingAddressItem ]
[self reconfigureCellsForItems:@[ _selectedItem, newlySelectedItem ]
inSectionWithIdentifier:SectionIdentifierShippingAddress]; inSectionWithIdentifier:SectionIdentifierShippingAddress];
_selectedItem = shippingAddressItem;
// Update the selected shipping address and its respective item.
NSInteger index = [model indexInItemTypeForIndexPath:indexPath];
DCHECK(index < (NSInteger)_shippingAddresses.size());
self.selectedShippingAddress = _shippingAddresses[index];
_selectedItem = newlySelectedItem;
}
[_delegate [_delegate
shippingAddressSelectionViewController:self shippingAddressSelectionViewController:self
selectedShippingAddress:self.selectedShippingAddress]; selectedShippingAddress:self.selectedShippingAddress];
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_PAYMENTS_SHIPPING_OPTION_SELECTION_COORDINATOR_H_
#define IOS_CHROME_BROWSER_PAYMENTS_SHIPPING_OPTION_SELECTION_COORDINATOR_H_
#import <UIKit/UIKit.h>
#include <vector>
#import "ios/chrome/browser/chrome_coordinator.h"
#include "ios/web/public/payments/payment_request.h"
@class ShippingOptionSelectionCoordinator;
@protocol ShippingOptionSelectionCoordinatorDelegate<NSObject>
// Notifies the delegate that the user has selected a shipping option.
- (void)shippingOptionSelectionCoordinator:
(ShippingOptionSelectionCoordinator*)coordinator
selectedShippingOption:
(web::PaymentShippingOption*)shippingOption;
// Notifies the delegate that the user has chosen to return to the previous
// screen without making a selection.
- (void)shippingOptionSelectionCoordinatorDidReturn:
(ShippingOptionSelectionCoordinator*)coordinator;
@end
// Coordinator responsible for creating and presenting the shipping option
// selection view controller. This view controller will be presented by the view
// controller provided in the initializer.
@interface ShippingOptionSelectionCoordinator : ChromeCoordinator
// The available shipping options to fulfill the payment request.
@property(nonatomic, assign) std::vector<web::PaymentShippingOption*>
shippingOptions;
// The shipping option selected by the user, if any.
@property(nonatomic, assign) web::PaymentShippingOption* selectedShippingOption;
// The delegate to be notified when the user selects a shipping option or
// returns without selecting one.
@property(nonatomic, weak) id<ShippingOptionSelectionCoordinatorDelegate>
delegate;
@end
#endif // IOS_CHROME_BROWSER_PAYMENTS_SHIPPING_OPTION_SELECTION_COORDINATOR_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/payments/shipping_option_selection_coordinator.h"
#import "base/ios/weak_nsobject.h"
#include "base/mac/scoped_nsobject.h"
#import "ios/chrome/browser/payments/shipping_option_selection_view_controller.h"
@interface ShippingOptionSelectionCoordinator ()<
ShippingOptionSelectionViewControllerDelegate> {
base::WeakNSProtocol<id<ShippingOptionSelectionCoordinatorDelegate>>
_delegate;
base::scoped_nsobject<ShippingOptionSelectionViewController> _viewController;
}
// Called when the user selects a shipping option. The cell is checked, the
// UI is locked so that the user can't interact with it, then the delegate is
// notified. The delay is here to let the user get a visual feedback of the
// selection before this view disappears.
- (void)delayedNotifyDelegateOfSelection;
@end
@implementation ShippingOptionSelectionCoordinator
@synthesize shippingOptions = _shippingOptions;
@synthesize selectedShippingOption = _selectedShippingOption;
- (id<ShippingOptionSelectionCoordinatorDelegate>)delegate {
return _delegate.get();
}
- (void)setDelegate:(id<ShippingOptionSelectionCoordinatorDelegate>)delegate {
_delegate.reset(delegate);
}
- (void)start {
_viewController.reset([[ShippingOptionSelectionViewController alloc] init]);
[_viewController setShippingOptions:_shippingOptions];
[_viewController setSelectedShippingOption:_selectedShippingOption];
[_viewController setDelegate:self];
[_viewController loadModel];
DCHECK(self.baseViewController.navigationController);
[self.baseViewController.navigationController
pushViewController:_viewController
animated:YES];
}
- (void)stop {
[self.baseViewController.navigationController popViewControllerAnimated:YES];
_viewController.reset();
}
#pragma mark - ShippingOptionSelectionViewControllerDelegate
- (void)shippingOptionSelectionViewController:
(ShippingOptionSelectionViewController*)controller
selectedShippingOption:
(web::PaymentShippingOption*)shippingOption {
_selectedShippingOption = shippingOption;
[self delayedNotifyDelegateOfSelection];
}
- (void)shippingOptionSelectionViewControllerDidReturn:
(ShippingOptionSelectionViewController*)controller {
[_delegate shippingOptionSelectionCoordinatorDidReturn:self];
}
- (void)delayedNotifyDelegateOfSelection {
_viewController.get().view.userInteractionEnabled = NO;
base::WeakNSObject<ShippingOptionSelectionCoordinator> weakSelf(self);
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.2 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
base::scoped_nsobject<ShippingOptionSelectionCoordinator> strongSelf(
[weakSelf retain]);
// Early return if the coordinator has been deallocated.
if (!strongSelf)
return;
_viewController.get().view.userInteractionEnabled = YES;
[_delegate shippingOptionSelectionCoordinator:self
selectedShippingOption:_selectedShippingOption];
});
}
@end
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/ios/wait_util.h"
#import "ios/chrome/browser/payments/shipping_option_selection_coordinator.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// Tests that invoking start and stop on the coordinator presents and dismisses
// the ShippingOptionSelectionViewController, respectively.
TEST(ShippingOptionSelectionCoordinatorTest, StartAndStop) {
@autoreleasepool {
UIViewController* base_view_controller =
[[[UIViewController alloc] init] autorelease];
UINavigationController* navigation_controller =
[[[UINavigationController alloc]
initWithRootViewController:base_view_controller] autorelease];
ShippingOptionSelectionCoordinator* coordinator =
[[[ShippingOptionSelectionCoordinator alloc]
initWithBaseViewController:base_view_controller] autorelease];
EXPECT_EQ(1u, [navigation_controller.viewControllers count]);
[coordinator start];
// Short delay to allow animation to complete.
base::test::ios::SpinRunLoopWithMaxDelay(
base::TimeDelta::FromSecondsD(1.0));
EXPECT_EQ(2u, [navigation_controller.viewControllers count]);
[coordinator stop];
// Short delay to allow animation to complete.
base::test::ios::SpinRunLoopWithMaxDelay(
base::TimeDelta::FromSecondsD(1.0));
EXPECT_EQ(1u, [navigation_controller.viewControllers count]);
}
}
} // namespace
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_PAYMENTS_SHIPPING_OPTION_SELECTION_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_PAYMENTS_SHIPPING_OPTION_SELECTION_VIEW_CONTROLLER_H_
#import <UIKit/UIKit.h>
#import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
#include "ios/web/public/payments/payment_request.h"
@class ShippingOptionSelectionViewController;
@protocol ShippingOptionSelectionViewControllerDelegate<NSObject>
- (void)shippingOptionSelectionViewController:
(ShippingOptionSelectionViewController*)controller
selectedShippingOption:
(web::PaymentShippingOption*)shippingOption;
- (void)shippingOptionSelectionViewControllerDidReturn:
(ShippingOptionSelectionViewController*)controller;
@end
// View controller responsible for presenting the available shipping options
// for selection by the user and communicating their choice to the supplied
// delegate.
@interface ShippingOptionSelectionViewController : CollectionViewController
// The available shipping options to fulfill the payment request.
@property(nonatomic, assign) std::vector<web::PaymentShippingOption*>
shippingOptions;
// The shipping option selected by the user, if any.
@property(nonatomic, assign) web::PaymentShippingOption* selectedShippingOption;
// The delegate to be notified when the user selects a shipping option or
// returns without selecting one.
@property(nonatomic, weak) id<ShippingOptionSelectionViewControllerDelegate>
delegate;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithStyle:(CollectionViewControllerStyle)style
NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_PAYMENTS_SHIPPING_OPTION_SELECTION_VIEW_CONTROLLER_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/payments/shipping_option_selection_view_controller.h"
#import "base/ios/weak_nsobject.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/payments/payment_request_utils.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
#import "ios/chrome/browser/ui/icons/chrome_icon.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
#include "ui/base/l10n/l10n_util.h"
NSString* const kShippingOptionSelectionCollectionViewId =
@"kShippingOptionSelectionCollectionViewId";
namespace {
const CGFloat kSeparatorEdgeInset = 14;
typedef NS_ENUM(NSInteger, SectionIdentifier) {
SectionIdentifierShippingOption = kSectionIdentifierEnumZero,
};
typedef NS_ENUM(NSInteger, ItemType) {
ItemTypeShippingOption = kItemTypeEnumZero, // This is a repeated item type.
};
} // namespace
@interface ShippingOptionSelectionViewController () {
base::WeakNSProtocol<id<ShippingOptionSelectionViewControllerDelegate>>
_delegate;
CollectionViewTextItem* _selectedItem;
}
// Called when the user presses the return button.
- (void)onReturn;
@end
@implementation ShippingOptionSelectionViewController
@synthesize shippingOptions = _shippingOptions;
@synthesize selectedShippingOption = _selectedShippingOption;
- (instancetype)init {
if ((self = [super initWithStyle:CollectionViewControllerStyleAppBar])) {
self.title = l10n_util::GetNSString(
IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE);
UIBarButtonItem* returnButton =
[ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon]
target:nil
action:@selector(onReturn)];
returnButton.accessibilityLabel = l10n_util::GetNSString(IDS_ACCNAME_BACK);
self.navigationItem.leftBarButtonItem = returnButton;
}
return self;
}
- (id<ShippingOptionSelectionViewControllerDelegate>)delegate {
return _delegate.get();
}
- (void)setDelegate:
(id<ShippingOptionSelectionViewControllerDelegate>)delegate {
_delegate.reset(delegate);
}
- (void)onReturn {
[_delegate shippingOptionSelectionViewControllerDidReturn:self];
}
#pragma mark - CollectionViewController methods
- (void)loadModel {
[super loadModel];
CollectionViewModel* model = self.collectionViewModel;
[model addSectionWithIdentifier:SectionIdentifierShippingOption];
for (size_t i = 0; i < _shippingOptions.size(); ++i) {
web::PaymentShippingOption* shippingOption = _shippingOptions[i];
CollectionViewTextItem* item = [[[CollectionViewTextItem alloc]
initWithType:ItemTypeShippingOption] autorelease];
item.text = base::SysUTF16ToNSString(shippingOption->label);
NSString* currencyCode =
base::SysUTF16ToNSString(shippingOption->amount.currency);
NSDecimalNumber* value = [NSDecimalNumber
decimalNumberWithString:SysUTF16ToNSString(
shippingOption->amount.value)];
item.detailText =
payment_request_utils::FormattedCurrencyString(value, currencyCode);
if (_selectedShippingOption == shippingOption) {
item.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
_selectedItem = item;
}
[model addItem:item
toSectionWithIdentifier:SectionIdentifierShippingOption];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
self.collectionView.accessibilityIdentifier =
kShippingOptionSelectionCollectionViewId;
// Customize collection view settings.
self.styler.cellStyle = MDCCollectionViewCellStyleCard;
self.styler.separatorInset =
UIEdgeInsetsMake(0, kSeparatorEdgeInset, 0, kSeparatorEdgeInset);
}
#pragma mark UICollectionViewDataSource
- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
cellForItemAtIndexPath:(nonnull NSIndexPath*)indexPath {
UICollectionViewCell* cell =
[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
NSInteger itemType =
[self.collectionViewModel itemTypeForIndexPath:indexPath];
DCHECK(ItemTypeShippingOption == itemType);
MDCCollectionViewTextCell* textCell =
base::mac::ObjCCastStrict<MDCCollectionViewTextCell>(cell);
textCell.textLabel.font = [MDCTypography body2Font];
textCell.textLabel.textColor = [[MDCPalette greyPalette] tint900];
textCell.detailTextLabel.font = [MDCTypography body1Font];
textCell.detailTextLabel.textColor = [[MDCPalette greyPalette] tint900];
return cell;
}
#pragma mark UICollectionViewDelegate
- (void)collectionView:(UICollectionView*)collectionView
didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
[super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
CollectionViewModel* model = self.collectionViewModel;
NSInteger itemType =
[self.collectionViewModel itemTypeForIndexPath:indexPath];
DCHECK(ItemTypeShippingOption == itemType);
NSIndexPath* currentlySelectedIndexPath = [self.collectionViewModel
indexPathForItem:_selectedItem
inSectionWithIdentifier:SectionIdentifierShippingOption];
if (currentlySelectedIndexPath != indexPath) {
// Update the cells.
CollectionViewItem* item = [model itemAtIndexPath:indexPath];
CollectionViewTextItem* newlySelectedItem =
base::mac::ObjCCastStrict<CollectionViewTextItem>(item);
newlySelectedItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
_selectedItem.accessoryType = MDCCollectionViewCellAccessoryNone;
[self reconfigureCellsForItems:@[ _selectedItem, newlySelectedItem ]
inSectionWithIdentifier:SectionIdentifierShippingOption];
// Update the selected shipping option and its respective item.
NSInteger index = [model indexInItemTypeForIndexPath:indexPath];
DCHECK(index < (NSInteger)_shippingOptions.size());
self.selectedShippingOption = _shippingOptions[index];
_selectedItem = newlySelectedItem;
}
[_delegate shippingOptionSelectionViewController:self
selectedShippingOption:self.selectedShippingOption];
}
#pragma mark MDCCollectionViewStylingDelegate
- (CGFloat)collectionView:(UICollectionView*)collectionView
cellHeightAtIndexPath:(NSIndexPath*)indexPath {
return MDCCellDefaultTwoLineHeight;
}
@end
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "base/mac/foundation_util.h"
#import "ios/chrome/browser/payments/shipping_option_selection_view_controller.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
#import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ios/web/public/payments/payment_request.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class ShippingOptionSelectionViewControllerTest
: public CollectionViewControllerTest {
protected:
CollectionViewController* NewController() override NS_RETURNS_RETAINED {
return [[ShippingOptionSelectionViewController alloc] init];
}
ShippingOptionSelectionViewController* ShippingOptionSelectionController() {
return base::mac::ObjCCastStrict<ShippingOptionSelectionViewController>(
controller());
}
};
// Tests that the correct number of items are displayed after loading the model
// and that the correct item appears to be selected.
TEST_F(ShippingOptionSelectionViewControllerTest, TestModel) {
CreateController();
CheckController();
CheckTitleWithId(IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE);
std::unique_ptr<web::PaymentShippingOption> option1(
new web::PaymentShippingOption());
std::unique_ptr<web::PaymentShippingOption> option2(
new web::PaymentShippingOption());
std::vector<web::PaymentShippingOption*> shippingOptions;
shippingOptions.push_back(option1.get());
shippingOptions.push_back(option2.get());
[ShippingOptionSelectionController() setShippingOptions:shippingOptions];
[ShippingOptionSelectionController()
setSelectedShippingOption:shippingOptions[0]];
[ShippingOptionSelectionController() loadModel];
ASSERT_EQ(1, NumberOfSections());
// One item for each of shipping options.
EXPECT_EQ(shippingOptions.size(),
static_cast<unsigned int>(NumberOfItemsInSection(0)));
// The first option should appear to be selected.
CollectionViewTextItem* item = GetCollectionViewItem(0, 0);
EXPECT_EQ(MDCCollectionViewCellAccessoryCheckmark, item.accessoryType);
item = GetCollectionViewItem(0, 1);
EXPECT_EQ(MDCCollectionViewCellAccessoryNone, item.accessoryType);
}
} // namespace
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