| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import <memory> |
| #import <string> |
| |
| #import "base/apple/foundation_util.h" |
| #import "base/strings/sys_string_conversions.h" |
| #import "base/values.h" |
| #import "components/strings/grit/components_strings.h" |
| #import "ios/chrome/browser/shared/ui/list_model/list_model.h" |
| #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_edit_item.h" |
| #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_header_footer_item.h" |
| #import "ios/chrome/browser/shared/ui/util/rtl_geometry.h" |
| #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" |
| #import "ios/chrome/browser/ui/autofill/card_expiration_date_fix_flow_view_bridge.h" |
| #import "ios/chrome/browser/ui/autofill/expiration_date_picker.h" |
| #import "ios/chrome/common/ui/colors/semantic_color_names.h" |
| #import "ui/base/l10n/l10n_util.h" |
| |
| CGFloat const kMainSection = 0; |
| CGFloat const kNumberOfRowsInMainSection = 1; |
| |
| namespace autofill { |
| |
| #pragma mark CardExpirationDateFixFlowViewBridge |
| |
| CardExpirationDateFixFlowViewBridge::CardExpirationDateFixFlowViewBridge( |
| CardExpirationDateFixFlowController* controller, |
| UIViewController* presenting_view_controller) |
| : controller_(controller), |
| presenting_view_controller_(presenting_view_controller) { |
| DCHECK(controller_); |
| DCHECK(presenting_view_controller_); |
| } |
| |
| CardExpirationDateFixFlowViewBridge::~CardExpirationDateFixFlowViewBridge() { |
| if (controller_) |
| controller_->OnDialogClosed(); |
| } |
| |
| void CardExpirationDateFixFlowViewBridge::Show() { |
| // Wrap CardExpirationDateFixFlowViewController with navigation controller to |
| // include a navigation bar. |
| view_controller_ = [[UINavigationController alloc] |
| initWithRootViewController:[[CardExpirationDateFixFlowViewController |
| alloc] initWithBridge:this]]; |
| [presenting_view_controller_ presentViewController:view_controller_ |
| animated:YES |
| completion:nil]; |
| } |
| |
| void CardExpirationDateFixFlowViewBridge::ControllerGone() { |
| controller_ = nullptr; |
| PerformClose(); |
| } |
| |
| CardExpirationDateFixFlowController* |
| CardExpirationDateFixFlowViewBridge::GetController() { |
| return controller_; |
| } |
| |
| void CardExpirationDateFixFlowViewBridge::OnConfirmedExpirationDate( |
| const std::u16string& month, |
| const std::u16string& year) { |
| controller_->OnAccepted(month, year); |
| PerformClose(); |
| } |
| |
| void CardExpirationDateFixFlowViewBridge::OnDismissed() { |
| controller_->OnDismissed(); |
| PerformClose(); |
| } |
| |
| void CardExpirationDateFixFlowViewBridge::PerformClose() { |
| base::WeakPtr<CardExpirationDateFixFlowViewBridge> weak_this = |
| weak_ptr_factory_.GetWeakPtr(); |
| [view_controller_ dismissViewControllerAnimated:YES |
| completion:^{ |
| if (weak_this) { |
| weak_this->DeleteSelf(); |
| } |
| }]; |
| } |
| |
| void CardExpirationDateFixFlowViewBridge::DeleteSelf() { |
| delete this; |
| } |
| |
| } // namespace autofill |
| |
| @interface CardExpirationDateFixFlowViewController () <UITextFieldDelegate, |
| UITableViewDelegate> { |
| UIBarButtonItem* _confirmButton; |
| NSString* _expirationDateMonth; |
| NSString* _expirationDateYear; |
| ExpirationDatePicker* _expirationDatePicker; |
| TableViewTextEditCell* _confirmExpirationDateCell; |
| TableViewTextHeaderFooterView* _footerView; |
| autofill::CardExpirationDateFixFlowViewBridge* _bridge; // weak |
| } |
| |
| @end |
| |
| @implementation CardExpirationDateFixFlowViewController |
| |
| - (instancetype)initWithBridge: |
| (autofill::CardExpirationDateFixFlowViewBridge*)bridge { |
| DCHECK(bridge); |
| |
| if (self = [super initWithStyle:UITableViewStyleGrouped]) { |
| _bridge = bridge; |
| self.title = |
| base::SysUTF16ToNSString(_bridge->GetController()->GetTitleText()); |
| } |
| |
| return self; |
| } |
| |
| #pragma mark - UIViewController |
| |
| - (void)viewDidLoad { |
| [super viewDidLoad]; |
| |
| self.tableView.delegate = self; |
| |
| autofill::CardExpirationDateFixFlowController* controller = |
| _bridge->GetController(); |
| |
| NSString* cancelButtonLabel = |
| base::SysUTF16ToNSString(controller->GetCancelButtonLabel()); |
| self.navigationItem.leftBarButtonItem = |
| [[UIBarButtonItem alloc] initWithTitle:cancelButtonLabel |
| style:UIBarButtonItemStylePlain |
| target:self |
| action:@selector(onCancel:)]; |
| NSString* saveButtonLabel = |
| base::SysUTF16ToNSString(controller->GetSaveButtonLabel()); |
| _confirmButton = |
| [[UIBarButtonItem alloc] initWithTitle:saveButtonLabel |
| style:UIBarButtonItemStylePlain |
| target:self |
| action:@selector(onConfirm:)]; |
| self.navigationItem.rightBarButtonItem = _confirmButton; |
| |
| _expirationDatePicker = |
| [[ExpirationDatePicker alloc] initWithFrame:CGRectZero]; |
| _expirationDatePicker.backgroundColor = [UIColor clearColor]; |
| __weak CardExpirationDateFixFlowViewController* weakSelf = self; |
| _expirationDatePicker.onDateSelected = ^(NSString* month, NSString* year) { |
| CardExpirationDateFixFlowViewController* strongSelf = weakSelf; |
| [strongSelf didSelectMonth:month year:year]; |
| }; |
| |
| _confirmExpirationDateCell = [[TableViewTextEditCell alloc] init]; |
| _confirmExpirationDateCell.selectionStyle = UITableViewCellSelectionStyleNone; |
| _confirmExpirationDateCell.useCustomSeparator = NO; |
| _confirmExpirationDateCell.textLabel.text = |
| base::SysUTF16ToNSString(controller->GetInputLabel()); |
| |
| UITextField* textField = _confirmExpirationDateCell.textField; |
| textField.inputView = _expirationDatePicker; |
| textField.textColor = [UIColor colorNamed:kBlueColor]; |
| textField.clearButtonMode = UITextFieldViewModeNever; |
| textField.delegate = self; |
| |
| _footerView = [[TableViewTextHeaderFooterView alloc] init]; |
| _footerView.subtitleLabel.textColor = [UIColor colorNamed:kRedColor]; |
| |
| // Set initial value. |
| [self didSelectMonth:_expirationDatePicker.month |
| year:_expirationDatePicker.year]; |
| } |
| |
| - (void)viewDidAppear:(BOOL)animated { |
| [super viewDidAppear:animated]; |
| [_confirmExpirationDateCell.textField becomeFirstResponder]; |
| } |
| |
| #pragma mark - UITableViewDelegate |
| |
| - (NSString*)tableView:(UITableView*)tableView |
| titleForHeaderInSection:(NSInteger)section { |
| DCHECK(section == kMainSection); |
| |
| return base::SysUTF16ToNSString(_bridge->GetController()->GetCardLabel()); |
| } |
| |
| - (UIView*)tableView:(UITableView*)tableView |
| viewForFooterInSection:(NSInteger)section { |
| DCHECK(section == kMainSection); |
| |
| return _footerView; |
| } |
| |
| #pragma mark - UITableViewDataSource |
| |
| - (NSInteger)tableView:(UITableView*)tableView |
| numberOfRowsInSection:(NSInteger)section { |
| DCHECK(section == kMainSection); |
| return kNumberOfRowsInMainSection; |
| } |
| |
| - (UITableViewCell*)tableView:(UITableView*)tableView |
| cellForRowAtIndexPath:(NSIndexPath*)indexPath { |
| DCHECK(indexPath.section == kMainSection); |
| |
| return _confirmExpirationDateCell; |
| } |
| |
| #pragma mark - UITextFieldDelegate |
| |
| - (BOOL)textField:(UITextField*)textField |
| shouldChangeCharactersInRange:(NSRange)range |
| replacementString:(NSString*)string { |
| return NO; /* Prevent any input from outside the date picker. */ |
| } |
| |
| #pragma mark - Private |
| |
| - (void)onCancel:(id)sender { |
| _bridge->OnDismissed(); |
| } |
| |
| - (void)onConfirm:(id)sender { |
| DCHECK(_expirationDateMonth.length > 0); |
| DCHECK(_expirationDateYear.length > 0); |
| |
| _bridge->OnConfirmedExpirationDate( |
| base::SysNSStringToUTF16(_expirationDateMonth), |
| base::SysNSStringToUTF16(_expirationDateYear)); |
| } |
| |
| - (void)didSelectMonth:(NSString*)month year:(NSString*)year { |
| _expirationDateYear = year; |
| _expirationDateMonth = month; |
| |
| NSString* dateSeparator = |
| base::SysUTF16ToNSString(_bridge->GetController()->GetDateSeparator()); |
| _confirmExpirationDateCell.textField.text = |
| [NSString stringWithFormat:@"%@%@%@", month, dateSeparator, year]; |
| |
| [self updateSaveButtonEnabledStatus]; |
| } |
| |
| - (void)updateSaveButtonEnabledStatus { |
| NSCalendar* calendar = NSCalendar.currentCalendar; |
| NSDateComponents* calendarComponents = |
| [calendar components:NSCalendarUnitMonth | NSCalendarUnitYear |
| fromDate:[NSDate date]]; |
| NSInteger currentYear = [calendarComponents year]; |
| NSInteger currentMonth = [calendarComponents month]; |
| |
| if ([_expirationDateYear intValue] < currentYear || |
| ([_expirationDateYear intValue] == currentYear && |
| [_expirationDateMonth intValue] < currentMonth)) { |
| _footerView.subtitleLabel.text = base::SysUTF16ToNSString( |
| _bridge->GetController()->GetInvalidDateError()); |
| _confirmButton.enabled = NO; |
| } else { |
| _footerView.subtitleLabel.text = nil; |
| _confirmButton.enabled = YES; |
| } |
| } |
| |
| @end |