| Index: ios/chrome/browser/payments/payment_request_edit_view_controller.mm
|
| diff --git a/ios/chrome/browser/payments/payment_request_edit_view_controller.mm b/ios/chrome/browser/payments/payment_request_edit_view_controller.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5e4fc8e49011b2ad7173bad66186c8152fef6e38
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/payments/payment_request_edit_view_controller.mm
|
| @@ -0,0 +1,247 @@
|
| +// 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/payment_request_edit_view_controller.h"
|
| +
|
| +#include "base/logging.h"
|
| +#import "base/mac/foundation_util.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "components/autofill/core/browser/validation.h"
|
| +#include "components/strings/grit/components_strings.h"
|
| +#import "ios/chrome/browser/payments/cells/payments_text_item.h"
|
| +#import "ios/chrome/browser/ui/settings/autofill_edit_accessory_view.h"
|
| +#import "ios/chrome/browser/ui/settings/cells/autofill_edit_item.h"
|
| +#import "ios/chrome/browser/ui/uikit_ui_util.h"
|
| +#include "ios/chrome/grit/ios_theme_resources.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +
|
| +#if !defined(__has_feature) || !__has_feature(objc_arc)
|
| +#error "This file requires ARC support."
|
| +#endif
|
| +
|
| +namespace {
|
| +
|
| +AutofillEditCell* AutofillEditCellForTextField(UITextField* textField) {
|
| + for (UIView* view = textField; view; view = [view superview]) {
|
| + AutofillEditCell* cell = base::mac::ObjCCast<AutofillEditCell>(view);
|
| + if (cell)
|
| + return cell;
|
| + }
|
| +
|
| + // There has to be a cell associated with this text field.
|
| + NOTREACHED();
|
| + return nil;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +@interface PaymentRequestEditViewController ()<AutofillEditAccessoryDelegate> {
|
| + // The currently focused cell. May be nil.
|
| + __weak AutofillEditCell* _currentEditingCell;
|
| +
|
| + AutofillEditAccessoryView* _accessoryView;
|
| +
|
| + // The PaymentRequest object owning an instance of web::PaymentRequest as
|
| + // provided by the page invoking the Payment Request API. This is a weak
|
| + // pointer and should outlive this class.
|
| + PaymentRequest* _paymentRequest;
|
| +}
|
| +@end
|
| +
|
| +@implementation PaymentRequestEditViewController
|
| +
|
| +- (instancetype)initWithPaymentRequest:(PaymentRequest*)paymentRequest {
|
| + self = [super initWithStyle:CollectionViewControllerStyleAppBar];
|
| + if (self) {
|
| + DCHECK(paymentRequest);
|
| + _paymentRequest = paymentRequest;
|
| + _accessoryView = [[AutofillEditAccessoryView alloc] initWithDelegate:self];
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)viewDidAppear:(BOOL)animated {
|
| + [super viewDidAppear:animated];
|
| + [[NSNotificationCenter defaultCenter]
|
| + addObserver:self
|
| + selector:@selector(keyboardDidShow)
|
| + name:UIKeyboardDidShowNotification
|
| + object:nil];
|
| +}
|
| +
|
| +- (void)viewWillDisappear:(BOOL)animated {
|
| + [super viewWillDisappear:animated];
|
| + [[NSNotificationCenter defaultCenter]
|
| + removeObserver:self
|
| + name:UIKeyboardDidShowNotification
|
| + object:nil];
|
| +}
|
| +
|
| +#pragma mark - CollectionViewController methods
|
| +
|
| +- (void)loadModel {
|
| + [super loadModel];
|
| + CollectionViewModel* model = self.collectionViewModel;
|
| +
|
| + // Iterate over the field definitions and add the respective sections and
|
| + // items.
|
| + for (const auto& field : [self editorFields]) {
|
| + [model addSectionWithIdentifier:field.section_id];
|
| + AutofillEditItem* item =
|
| + [[AutofillEditItem alloc] initWithType:field.item_type];
|
| + NSString* labelFormat = field.required ? @"%@*" : @"%@";
|
| + item.textFieldName = [NSString
|
| + stringWithFormat:labelFormat, base::SysUTF16ToNSString(field.label)];
|
| + item.textFieldEnabled = YES;
|
| + item.required = field.required;
|
| + item.autofillType = field.data_type;
|
| + [model addItem:item toSectionWithIdentifier:field.section_id];
|
| + }
|
| +}
|
| +
|
| +#pragma mark - UITextFieldDelegate
|
| +
|
| +- (void)textFieldDidBeginEditing:(UITextField*)textField {
|
| + _currentEditingCell = AutofillEditCellForTextField(textField);
|
| + [textField setInputAccessoryView:_accessoryView];
|
| + [self updateAccessoryViewButtonState];
|
| +}
|
| +
|
| +- (void)textFieldDidEndEditing:(UITextField*)textField {
|
| + DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField));
|
| + [textField setInputAccessoryView:nil];
|
| + _currentEditingCell = nil;
|
| +}
|
| +
|
| +- (BOOL)textFieldShouldReturn:(UITextField*)textField {
|
| + DCHECK([_currentEditingCell textField] == textField);
|
| + [self nextPressed];
|
| + return NO;
|
| +}
|
| +
|
| +#pragma mark - AutofillEditAccessoryDelegate
|
| +
|
| +- (void)nextPressed {
|
| + AutofillEditCell* nextCell = [self nextTextFieldWithOffset:1];
|
| + if (nextCell)
|
| + [nextCell.textField becomeFirstResponder];
|
| +}
|
| +
|
| +- (void)previousPressed {
|
| + AutofillEditCell* previousCell = [self nextTextFieldWithOffset:-1];
|
| + if (previousCell)
|
| + [previousCell.textField becomeFirstResponder];
|
| +}
|
| +
|
| +- (void)closePressed {
|
| + [[_currentEditingCell textField] resignFirstResponder];
|
| +}
|
| +
|
| +#pragma mark - Protected methods
|
| +
|
| +- (std::vector<EditorField>)editorFields {
|
| + return std::vector<EditorField>();
|
| +}
|
| +
|
| +- (NSIndexPath*)indexPathForCurrentTextField {
|
| + DCHECK(_currentEditingCell);
|
| + NSIndexPath* indexPath =
|
| + [[self collectionView] indexPathForCell:_currentEditingCell];
|
| + DCHECK(indexPath);
|
| + return indexPath;
|
| +}
|
| +
|
| +- (NSString*)validateValue:(NSString*)value
|
| + autofillType:(autofill::ServerFieldType)autofillType
|
| + required:(BOOL)required {
|
| + base::string16 errorMessage;
|
| + if (value.length != 0) {
|
| + base::string16 valueString = base::SysNSStringToUTF16(value);
|
| + autofillType == autofill::CREDIT_CARD_NUMBER
|
| + ? autofill::IsValidCreditCardNumberForBasicCardNetworks(
|
| + valueString, _paymentRequest->supported_card_networks(),
|
| + &errorMessage)
|
| + : autofill::IsValidForType(valueString, autofillType, &errorMessage);
|
| + return base::SysUTF16ToNSString(errorMessage);
|
| + }
|
| +
|
| + if (required) {
|
| + errorMessage = l10n_util::GetStringUTF16(
|
| + IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE);
|
| + }
|
| +
|
| + return base::SysUTF16ToNSString(errorMessage);
|
| +}
|
| +
|
| +- (void)addOrRemoveErrorItemWithType:(NSInteger)itemType
|
| + errorMessage:(NSString*)errorMessage
|
| + inSectionWithIdentifier:(NSInteger)sectionIdentifier {
|
| + CollectionViewModel* model = self.collectionViewModel;
|
| + if ([model hasItemForItemType:itemType sectionIdentifier:sectionIdentifier]) {
|
| + [model removeItemWithType:itemType
|
| + fromSectionWithIdentifier:sectionIdentifier];
|
| + }
|
| +
|
| + if (errorMessage.length != 0) {
|
| + PaymentsTextItem* errorMessageItem =
|
| + [[PaymentsTextItem alloc] initWithType:itemType];
|
| + errorMessageItem.text = errorMessage;
|
| + errorMessageItem.image = NativeImage(IDR_IOS_PAYMENTS_WARNING);
|
| + [model addItem:errorMessageItem toSectionWithIdentifier:sectionIdentifier];
|
| + }
|
| +
|
| + // Update the entire section.
|
| + NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier];
|
| + [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:section]];
|
| +}
|
| +
|
| +#pragma mark - Helper methods
|
| +
|
| +- (NSIndexPath*)indexPathWithSectionOffset:(NSInteger)offset
|
| + fromPath:(NSIndexPath*)indexPath {
|
| + DCHECK(indexPath);
|
| + DCHECK(offset);
|
| +
|
| + NSInteger nextSection = [indexPath section] + offset;
|
| + if (nextSection >= 0 &&
|
| + nextSection < [[self collectionView] numberOfSections])
|
| + return [NSIndexPath indexPathForRow:[indexPath row] inSection:nextSection];
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (AutofillEditCell*)nextTextFieldWithOffset:(NSInteger)offset {
|
| + UICollectionView* collectionView = [self collectionView];
|
| + NSIndexPath* currentCellPath = [self indexPathForCurrentTextField];
|
| + DCHECK(currentCellPath);
|
| + for (NSIndexPath* nextCellPath =
|
| + [self indexPathWithSectionOffset:offset fromPath:currentCellPath];
|
| + nextCellPath;
|
| + nextCellPath =
|
| + [self indexPathWithSectionOffset:offset fromPath:nextCellPath]) {
|
| + id nextCell = [collectionView cellForItemAtIndexPath:nextCellPath];
|
| + if ([nextCell isMemberOfClass:[AutofillEditCell class]]) {
|
| + return base::mac::ObjCCastStrict<AutofillEditCell>(
|
| + [collectionView cellForItemAtIndexPath:nextCellPath]);
|
| + }
|
| + }
|
| + return nil;
|
| +}
|
| +
|
| +- (void)updateAccessoryViewButtonState {
|
| + AutofillEditCell* previousCell = [self nextTextFieldWithOffset:-1];
|
| + [[_accessoryView previousButton] setEnabled:previousCell != nil];
|
| +
|
| + AutofillEditCell* nextCell = [self nextTextFieldWithOffset:1];
|
| + [[_accessoryView nextButton] setEnabled:nextCell != nil];
|
| +}
|
| +
|
| +#pragma mark - Keyboard handling
|
| +
|
| +- (void)keyboardDidShow {
|
| + [self.collectionView scrollRectToVisible:[_currentEditingCell frame]
|
| + animated:YES];
|
| +}
|
| +
|
| +@end
|
|
|