OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/autofill/form_suggestion_label.h" |
| 6 |
| 7 #include <cmath> |
| 8 |
| 9 #import <QuartzCore/QuartzCore.h> |
| 10 |
| 11 #include "base/strings/sys_string_conversions.h" |
| 12 #include "components/autofill/core/browser/credit_card.h" |
| 13 #import "components/autofill/ios/browser/form_suggestion.h" |
| 14 #import "ios/chrome/browser/autofill/form_suggestion_view_client.h" |
| 15 #include "ios/chrome/browser/ui/ui_util.h" |
| 16 |
| 17 namespace { |
| 18 |
| 19 // The button corner radius. |
| 20 const CGFloat kCornerRadius = 3.0f; |
| 21 |
| 22 // The width of the border in the button background image. |
| 23 const CGFloat kBorderWidth = 1.0f; |
| 24 |
| 25 // Font size of button titles. |
| 26 const CGFloat kIpadFontSize = 15.0f; |
| 27 const CGFloat kIphoneFontSize = 13.0f; |
| 28 |
| 29 // The grayscale value of the color object. |
| 30 const CGFloat kTitleColor = 51.0f / 255.0f; |
| 31 |
| 32 // The alpha value of the suggestion's description label. |
| 33 const CGFloat kDescriptionLabelAlpha = 0.54f; |
| 34 |
| 35 // The edge inset for background image. |
| 36 const CGFloat kBackgroundImageEdgeInsetSize = 8.0f; |
| 37 // The space between items in the label. |
| 38 const CGFloat kSpacing = 8.0f; |
| 39 |
| 40 // Structure that record the image for each icon. |
| 41 struct IconImageMap { |
| 42 const char* const icon_name; |
| 43 NSString* image_name; |
| 44 }; |
| 45 |
| 46 const IconImageMap kCreditCardIconImageMap[] = { |
| 47 {autofill::kAmericanExpressCard, @"autofill_card_american_express"}, |
| 48 {autofill::kDiscoverCard, @"autofill_card_discover"}, |
| 49 {autofill::kMasterCard, @"autofill_card_mastercard"}, |
| 50 {autofill::kVisaCard, @"autofill_card_visa"}, |
| 51 {autofill::kDinersCard, @"autofill_card_diners"}, |
| 52 {autofill::kGenericCard, @"autofill_card_generic"}, |
| 53 {autofill::kJCBCard, @"autofill_card_jcb"}, |
| 54 {autofill::kUnionPay, @"autofill_card_unionpay"}, |
| 55 }; |
| 56 |
| 57 // Creates a label with the given |text| and |alpha| suitable for use in a |
| 58 // suggestion button in the keyboard accessory view. |
| 59 UILabel* TextLabel(NSString* text, CGFloat alpha) { |
| 60 base::scoped_nsobject<UILabel> label([[UILabel alloc] init]); |
| 61 [label setText:text]; |
| 62 UIFont* font = IsIPadIdiom() ? [UIFont systemFontOfSize:kIpadFontSize] |
| 63 : [UIFont systemFontOfSize:kIphoneFontSize]; |
| 64 [label setFont:font]; |
| 65 [label setTextColor:[UIColor colorWithWhite:kTitleColor alpha:alpha]]; |
| 66 [label setBackgroundColor:[UIColor clearColor]]; |
| 67 [label sizeToFit]; |
| 68 return label.autorelease(); |
| 69 } |
| 70 |
| 71 } // namespace |
| 72 |
| 73 @interface FormSuggestionLabel () |
| 74 |
| 75 @property(nonatomic, readonly) UIColor* normalBackgroundColor; |
| 76 @property(nonatomic, readonly) UIColor* pressedBackgroundColor; |
| 77 |
| 78 // Returns the color generated from the image named |imageName| resized to |
| 79 // |rect|. |
| 80 - (UIColor*)backgroundColorFromImageNamed:(NSString*)imageName |
| 81 inRect:(CGRect)rect; |
| 82 // Returns the name of the image for credit card icon. |
| 83 + (NSString*)imageNameForCreditCardIcon:(NSString*)icon; |
| 84 @end |
| 85 |
| 86 @implementation FormSuggestionLabel { |
| 87 // Client of this view. |
| 88 base::WeakNSProtocol<id<FormSuggestionViewClient>> client_; |
| 89 base::scoped_nsobject<FormSuggestion> suggestion_; |
| 90 |
| 91 // Background color when the label is not pressed. |
| 92 base::scoped_nsobject<UIColor> normalBackgroundColor_; |
| 93 // Background color when the label is pressed. |
| 94 base::scoped_nsobject<UIColor> pressedBackgroundColor_; |
| 95 } |
| 96 |
| 97 - (id)initWithSuggestion:(FormSuggestion*)suggestion |
| 98 proposedFrame:(CGRect)proposedFrame |
| 99 client:(id<FormSuggestionViewClient>)client { |
| 100 // TODO(jimblackler): implement sizeThatFits: and layoutSubviews, and perform |
| 101 // layout in those methods instead of in the designated initializer. |
| 102 self = [super initWithFrame:CGRectZero]; |
| 103 if (self) { |
| 104 suggestion_.reset([suggestion retain]); |
| 105 client_.reset(client); |
| 106 |
| 107 const CGFloat frameHeight = CGRectGetHeight(proposedFrame); |
| 108 CGFloat currentX = kBorderWidth + kSpacing; |
| 109 |
| 110 UIImage* iconImage = [UIImage imageNamed: |
| 111 [FormSuggestionLabel imageNameForCreditCardIcon:suggestion.icon]]; |
| 112 if (iconImage) { |
| 113 UIImageView* iconView = |
| 114 [[[UIImageView alloc] initWithImage:iconImage] autorelease]; |
| 115 const CGFloat iconY = |
| 116 std::floor((frameHeight - iconImage.size.height) / 2.0f); |
| 117 iconView.frame = CGRectMake(currentX, iconY, iconImage.size.width, |
| 118 iconImage.size.height); |
| 119 [self addSubview:iconView]; |
| 120 currentX += CGRectGetWidth(iconView.frame) + kSpacing; |
| 121 } |
| 122 |
| 123 UILabel* label = TextLabel(suggestion.value, 1.0f); |
| 124 const CGFloat labelY = |
| 125 std::floor(frameHeight / 2.0f - CGRectGetMidY(label.frame)); |
| 126 label.frame = CGRectMake(currentX, labelY, CGRectGetWidth(label.frame), |
| 127 CGRectGetHeight(label.frame)); |
| 128 [self addSubview:label]; |
| 129 currentX += CGRectGetWidth(label.frame) + kSpacing; |
| 130 |
| 131 if (suggestion.displayDescription) { |
| 132 UILabel* description = |
| 133 TextLabel(suggestion.displayDescription, kDescriptionLabelAlpha); |
| 134 const CGFloat descriptionY = |
| 135 std::floor(frameHeight / 2.0f - CGRectGetMidY(description.frame)); |
| 136 description.frame = |
| 137 CGRectMake(currentX, descriptionY, CGRectGetWidth(description.frame), |
| 138 CGRectGetHeight(description.frame)); |
| 139 [self addSubview:description]; |
| 140 currentX += CGRectGetWidth(description.frame) + kSpacing; |
| 141 } |
| 142 |
| 143 currentX += kBorderWidth; |
| 144 |
| 145 self.frame = CGRectMake(proposedFrame.origin.x, proposedFrame.origin.y, |
| 146 currentX, proposedFrame.size.height); |
| 147 [self setBackgroundColor:[self normalBackgroundColor]]; |
| 148 [[self layer] setCornerRadius:kCornerRadius]; |
| 149 |
| 150 [self setClipsToBounds:YES]; |
| 151 [self setIsAccessibilityElement:YES]; |
| 152 [self setAccessibilityLabel:suggestion.value]; |
| 153 [self setUserInteractionEnabled:YES]; |
| 154 } |
| 155 |
| 156 return self; |
| 157 } |
| 158 |
| 159 - (id)initWithFrame:(CGRect)frame { |
| 160 NOTREACHED(); |
| 161 return nil; |
| 162 } |
| 163 |
| 164 - (void)layoutSubviews { |
| 165 // Resets the colors so the size will be updated in their getters. |
| 166 normalBackgroundColor_.reset(); |
| 167 pressedBackgroundColor_.reset(); |
| 168 [super layoutSubviews]; |
| 169 } |
| 170 |
| 171 #pragma mark - |
| 172 #pragma mark UIResponder |
| 173 |
| 174 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { |
| 175 [self setBackgroundColor:self.pressedBackgroundColor]; |
| 176 } |
| 177 |
| 178 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { |
| 179 [self setBackgroundColor:self.normalBackgroundColor]; |
| 180 } |
| 181 |
| 182 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { |
| 183 [self setBackgroundColor:self.normalBackgroundColor]; |
| 184 [client_ didSelectSuggestion:suggestion_]; |
| 185 } |
| 186 |
| 187 #pragma mark - |
| 188 #pragma mark Private |
| 189 |
| 190 - (UIColor*)normalBackgroundColor { |
| 191 if (!normalBackgroundColor_) { |
| 192 normalBackgroundColor_.reset( |
| 193 [[self backgroundColorFromImageNamed:@"autofill_button" |
| 194 inRect:self.bounds] retain]); |
| 195 } |
| 196 return normalBackgroundColor_; |
| 197 } |
| 198 |
| 199 - (UIColor*)pressedBackgroundColor { |
| 200 if (!pressedBackgroundColor_) { |
| 201 pressedBackgroundColor_.reset( |
| 202 [[self backgroundColorFromImageNamed:@"autofill_button_pressed" |
| 203 inRect:self.bounds] retain]); |
| 204 } |
| 205 return pressedBackgroundColor_; |
| 206 } |
| 207 |
| 208 - (UIColor*)backgroundColorFromImageNamed:(NSString*)imageName |
| 209 inRect:(CGRect)rect { |
| 210 UIEdgeInsets edgeInsets = UIEdgeInsetsMake( |
| 211 kBackgroundImageEdgeInsetSize, kBackgroundImageEdgeInsetSize, |
| 212 kBackgroundImageEdgeInsetSize, kBackgroundImageEdgeInsetSize); |
| 213 UIImage* image = |
| 214 [[UIImage imageNamed:imageName] resizableImageWithCapInsets:edgeInsets]; |
| 215 |
| 216 UIGraphicsBeginImageContextWithOptions(rect.size, NO, |
| 217 UIScreen.mainScreen.scale); |
| 218 [image drawInRect:rect]; |
| 219 UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext(); |
| 220 UIGraphicsEndImageContext(); |
| 221 |
| 222 return [UIColor colorWithPatternImage:resizedImage]; |
| 223 } |
| 224 |
| 225 + (NSString*)imageNameForCreditCardIcon:(NSString*)icon { |
| 226 if (!icon || [icon length] == 0) { |
| 227 return nil; |
| 228 } |
| 229 std::string iconName(base::SysNSStringToUTF8(icon)); |
| 230 for (size_t i = 0; i < arraysize(kCreditCardIconImageMap); ++i) { |
| 231 if (iconName.compare(kCreditCardIconImageMap[i].icon_name) == 0) { |
| 232 return kCreditCardIconImageMap[i].image_name; |
| 233 } |
| 234 } |
| 235 return nil; |
| 236 } |
| 237 |
| 238 @end |
OLD | NEW |