blob: dae7e5587cc7fa8cbe3e9a4304a25fc74b5d8f49 [file] [log] [blame]
// Copyright 2018 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/ui/autofill/manual_fill/manual_fill_card_cell.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/card_list_delegate.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/credit_card.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_cell_utils.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_content_delegate.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/uicolor_manualfill.h"
#import "ios/chrome/browser/ui/list_model/list_model.h"
#import "ios/chrome/common/ui_util/constraints_ui_util.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface ManualFillCardItem ()
// The content delegate for this item.
@property(nonatomic, weak, readonly) id<ManualFillContentDelegate>
contentDelegate;
// The navigation delegate for this item.
@property(nonatomic, weak, readonly) id<CardListDelegate> navigationDelegate;
// The credit card for this item.
@property(nonatomic, readonly) ManualFillCreditCard* card;
@end
@implementation ManualFillCardItem
@synthesize contentDelegate = _contentDelegate;
@synthesize navigationDelegate = _navigationDelegate;
@synthesize card = _card;
- (instancetype)initWithCreditCard:(ManualFillCreditCard*)card
contentDelegate:
(id<ManualFillContentDelegate>)contentDelegate
navigationDelegate:(id<CardListDelegate>)navigationDelegate {
self = [super initWithType:kItemTypeEnumZero];
if (self) {
_contentDelegate = contentDelegate;
_navigationDelegate = navigationDelegate;
_card = card;
self.cellClass = [ManualFillCardCell class];
}
return self;
}
- (void)configureCell:(ManualFillCardCell*)cell
withStyler:(ChromeTableViewStyler*)styler {
[super configureCell:cell withStyler:styler];
[cell setUpWithCreditCard:self.card
contentDelegate:self.contentDelegate
navigationDelegate:self.navigationDelegate];
}
@end
namespace {
// Left and right margins of the cell content.
static const CGFloat sideMargins = 16;
// Margin left and right of expiration buttons.
static const CGFloat ExpirationMarginWidth = 16.0;
} // namespace
@interface ManualFillCardCell ()
// The label with the site name and host.
@property(nonatomic, strong) UILabel* cardLabel;
// A button showing the card number.
@property(nonatomic, strong) UIButton* cardNumberButton;
// A button showing the cardholder name.
@property(nonatomic, strong) UIButton* cardholderButton;
// A button showing the expiration month.
@property(nonatomic, strong) UIButton* expirationMonthButton;
// A button showing the expiration year.
@property(nonatomic, strong) UIButton* expirationYearButton;
// The content delegate for this item.
@property(nonatomic, weak) id<ManualFillContentDelegate> contentDelegate;
// The navigation delegate for this item.
@property(nonatomic, weak) id<CardListDelegate> navigationDelegate;
// The credit card data for this cell.
@property(nonatomic, assign) ManualFillCreditCard* card;
@end
@implementation ManualFillCardCell
#pragma mark - Public
- (void)prepareForReuse {
[super prepareForReuse];
self.cardLabel.text = @"";
[self.cardNumberButton setTitle:@"" forState:UIControlStateNormal];
[self.cardholderButton setTitle:@"" forState:UIControlStateNormal];
[self.expirationMonthButton setTitle:@"" forState:UIControlStateNormal];
[self.expirationYearButton setTitle:@"" forState:UIControlStateNormal];
self.contentDelegate = nil;
self.navigationDelegate = nil;
self.card = nil;
}
- (void)setUpWithCreditCard:(ManualFillCreditCard*)card
contentDelegate:(id<ManualFillContentDelegate>)contentDelegate
navigationDelegate:(id<CardListDelegate>)navigationDelegate {
if (self.contentView.subviews.count == 0) {
[self createViewHierarchy];
}
self.contentDelegate = contentDelegate;
self.navigationDelegate = navigationDelegate;
self.card = card;
NSString* cardName = @"";
if (card.bankName.length) {
cardName = card.network;
} else {
cardName =
[NSString stringWithFormat:@"%@ %@", card.network, card.bankName];
}
NSMutableAttributedString* attributedString =
[[NSMutableAttributedString alloc]
initWithString:cardName
attributes:@{
NSForegroundColorAttributeName : UIColor.blackColor,
NSFontAttributeName :
[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]
}];
self.cardLabel.attributedText = attributedString;
[self.cardNumberButton setTitle:card.obfuscatedNumber
forState:UIControlStateNormal];
[self.cardholderButton setTitle:card.cardHolder
forState:UIControlStateNormal];
[self.expirationMonthButton setTitle:card.expirationMonth
forState:UIControlStateNormal];
[self.expirationYearButton setTitle:card.expirationYear
forState:UIControlStateNormal];
}
#pragma mark - Private
// Creates and sets up the view hierarchy.
- (void)createViewHierarchy {
self.selectionStyle = UITableViewCellSelectionStyleNone;
UIView* grayLine = [[UIView alloc] init];
grayLine.backgroundColor = UIColor.cr_manualFillGrayLineColor;
grayLine.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:grayLine];
self.cardLabel = CreateLabel();
[self.contentView addSubview:self.cardLabel];
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.cardLabel ], grayLine,
0);
self.cardNumberButton =
CreateButtonWithSelectorAndTarget(@selector(userDidTapCardNumber:), self);
[self.contentView addSubview:self.cardNumberButton];
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.cardNumberButton ],
grayLine, 0);
self.cardholderButton =
CreateButtonWithSelectorAndTarget(@selector(userDidTapCardInfo:), self);
[self.contentView addSubview:self.cardholderButton];
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.cardholderButton ],
grayLine, 0);
// Expiration line.
self.expirationMonthButton =
CreateButtonWithSelectorAndTarget(@selector(userDidTapCardInfo:), self);
HorizontalConstraintsMarginForButtonWithWidth(self.expirationMonthButton,
ExpirationMarginWidth);
[self.contentView addSubview:self.expirationMonthButton];
self.expirationYearButton =
CreateButtonWithSelectorAndTarget(@selector(userDidTapCardInfo:), self);
HorizontalConstraintsMarginForButtonWithWidth(self.expirationYearButton,
ExpirationMarginWidth);
[self.contentView addSubview:self.expirationYearButton];
UILabel* expirationSeparatorLabel = CreateLabel();
expirationSeparatorLabel.text = @"/";
[self.contentView addSubview:expirationSeparatorLabel];
SyncBaselinesForViewsOnView(
@[ expirationSeparatorLabel, self.expirationYearButton ],
self.expirationMonthButton);
HorizontalConstraintsForViewsOnGuideWithShift(
@[
self.expirationMonthButton, expirationSeparatorLabel,
self.expirationYearButton
],
grayLine, -ExpirationMarginWidth);
VerticalConstraintsSpacingForViewsInContainer(
@[
self.cardLabel, self.cardNumberButton, self.cardholderButton,
self.expirationMonthButton
],
self.contentView);
id<LayoutGuideProvider> safeArea = self.contentView.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
// Common vertical constraints.
[grayLine.bottomAnchor
constraintEqualToAnchor:self.contentView.bottomAnchor],
[grayLine.heightAnchor constraintEqualToConstant:1],
// Horizontal constraints.
[grayLine.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor
constant:sideMargins],
[safeArea.trailingAnchor constraintEqualToAnchor:grayLine.trailingAnchor
constant:sideMargins],
]];
}
- (void)userDidTapCardNumber:(UIButton*)sender {
NSString* number = self.card.number;
if (!number.length) {
[self.navigationDelegate requestFullCreditCard:self.card];
} else {
[self.contentDelegate userDidPickContent:number isSecure:NO];
}
}
- (void)userDidTapCardInfo:(UIButton*)sender {
[self.contentDelegate userDidPickContent:sender.titleLabel.text isSecure:NO];
}
@end