| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/today_extension/interactive_label.h" | 5 #import "ios/chrome/today_extension/interactive_label.h" |
| 6 | 6 |
| 7 #import "base/mac/scoped_block.h" | 7 #import "base/mac/scoped_block.h" |
| 8 #import "base/mac/scoped_nsobject.h" | 8 #import "base/mac/scoped_nsobject.h" |
| 9 #import "ios/chrome/common/string_util.h" | 9 #import "ios/chrome/common/string_util.h" |
| 10 #include "ios/chrome/today_extension/transparent_button.h" | 10 #include "ios/chrome/today_extension/transparent_button.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 - (BOOL)canBecomeFirstResponder { | 27 - (BOOL)canBecomeFirstResponder { |
| 28 return NO; | 28 return NO; |
| 29 } | 29 } |
| 30 | 30 |
| 31 @end | 31 @end |
| 32 | 32 |
| 33 @implementation InteractiveLabel { | 33 @implementation InteractiveLabel { |
| 34 base::scoped_nsobject<NSString> _labelString; | 34 base::scoped_nsobject<NSString> _labelString; |
| 35 base::scoped_nsobject<NSString> _buttonString; | 35 base::scoped_nsobject<NSString> _buttonString; |
| 36 base::scoped_nsobject<UITextView> _label; | 36 base::scoped_nsobject<UITextView> _label; |
| 37 base::mac::ScopedBlock<ProceduralBlock> _linkBlock; | 37 ProceduralBlock _linkBlock; |
| 38 base::mac::ScopedBlock<ProceduralBlock> _buttonBlock; | 38 ProceduralBlock _buttonBlock; |
| 39 base::scoped_nsobject<TransparentButton> _activationButton; | 39 base::scoped_nsobject<TransparentButton> _activationButton; |
| 40 NSRange _buttonRange; | 40 NSRange _buttonRange; |
| 41 base::scoped_nsobject<NSMutableAttributedString> _attributedText; | 41 base::scoped_nsobject<NSMutableAttributedString> _attributedText; |
| 42 UIEdgeInsets _insets; | 42 UIEdgeInsets _insets; |
| 43 CGFloat _currentWidth; | 43 CGFloat _currentWidth; |
| 44 | 44 |
| 45 // These constraints set the position of the button inside | 45 // These constraints set the position of the button inside |
| 46 base::scoped_nsobject<NSLayoutConstraint> _buttonTopConstraint; | 46 base::scoped_nsobject<NSLayoutConstraint> _buttonTopConstraint; |
| 47 base::scoped_nsobject<NSLayoutConstraint> _buttonLeftConstraint; | 47 base::scoped_nsobject<NSLayoutConstraint> _buttonLeftConstraint; |
| 48 base::scoped_nsobject<NSLayoutConstraint> _buttonHeightConstraint; | 48 base::scoped_nsobject<NSLayoutConstraint> _buttonHeightConstraint; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 60 self = [super initWithFrame:frame]; | 60 self = [super initWithFrame:frame]; |
| 61 if (self) { | 61 if (self) { |
| 62 _insets = insets; | 62 _insets = insets; |
| 63 _currentWidth = frame.size.width; | 63 _currentWidth = frame.size.width; |
| 64 // When the first character of the UITextView text as a NSLinkAttributeName | 64 // When the first character of the UITextView text as a NSLinkAttributeName |
| 65 // attribute, the lineSpacing attribute of the paragraph style is ignored. | 65 // attribute, the lineSpacing attribute of the paragraph style is ignored. |
| 66 // Add a zero width space so the first character is never in a link. | 66 // Add a zero width space so the first character is never in a link. |
| 67 NSString* prefixedString = | 67 NSString* prefixedString = |
| 68 [NSString stringWithFormat:@"\u200B%@", labelString]; | 68 [NSString stringWithFormat:@"\u200B%@", labelString]; |
| 69 _labelString.reset([prefixedString copy]); | 69 _labelString.reset([prefixedString copy]); |
| 70 _linkBlock.reset(linkBlock, base::scoped_policy::RETAIN); | 70 _linkBlock = [linkBlock copy]; |
| 71 | 71 |
| 72 _label.reset([[NoSelectionUITextView alloc] initWithFrame:CGRectZero]); | 72 _label.reset([[NoSelectionUITextView alloc] initWithFrame:CGRectZero]); |
| 73 [_label setTranslatesAutoresizingMaskIntoConstraints:NO]; | 73 [_label setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 74 [_label setDelegate:self]; | 74 [_label setDelegate:self]; |
| 75 [_label setBackgroundColor:[UIColor clearColor]]; | 75 [_label setBackgroundColor:[UIColor clearColor]]; |
| 76 [_label setSelectable:YES]; | 76 [_label setSelectable:YES]; |
| 77 [_label setEditable:NO]; | 77 [_label setEditable:NO]; |
| 78 // We want to get rid of the padding of the text in the UITextView. | 78 // We want to get rid of the padding of the text in the UITextView. |
| 79 [_label setTextContainerInset:UIEdgeInsetsZero]; | 79 [_label setTextContainerInset:UIEdgeInsetsZero]; |
| 80 [[_label textContainer] setLineFragmentPadding:0]; | 80 [[_label textContainer] setLineFragmentPadding:0]; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 92 | 92 |
| 93 NSRange linkRange; | 93 NSRange linkRange; |
| 94 NSString* text = ParseStringWithLink(_labelString, &linkRange); | 94 NSString* text = ParseStringWithLink(_labelString, &linkRange); |
| 95 [_label setAccessibilityTraits:[_label accessibilityTraits] | | 95 [_label setAccessibilityTraits:[_label accessibilityTraits] | |
| 96 UIAccessibilityTraitStaticText]; | 96 UIAccessibilityTraitStaticText]; |
| 97 NSString* buttonText = nil; | 97 NSString* buttonText = nil; |
| 98 _buttonRange = NSMakeRange(0, 0); | 98 _buttonRange = NSMakeRange(0, 0); |
| 99 BOOL showButton = buttonString && buttonBlock; | 99 BOOL showButton = buttonString && buttonBlock; |
| 100 if (showButton) { | 100 if (showButton) { |
| 101 _buttonString.reset([buttonString copy]); | 101 _buttonString.reset([buttonString copy]); |
| 102 _buttonBlock.reset(buttonBlock, base::scoped_policy::RETAIN); | 102 _buttonBlock = [buttonBlock copy]; |
| 103 _activationButton.reset( | 103 _activationButton.reset( |
| 104 [[TransparentButton alloc] initWithFrame:CGRectZero]); | 104 [[TransparentButton alloc] initWithFrame:CGRectZero]); |
| 105 [_activationButton addTarget:self | 105 [_activationButton addTarget:self |
| 106 action:@selector(buttonPressed:) | 106 action:@selector(buttonPressed:) |
| 107 forControlEvents:UIControlEventTouchUpInside]; | 107 forControlEvents:UIControlEventTouchUpInside]; |
| 108 [_activationButton setBackgroundColor:[UIColor clearColor]]; | 108 [_activationButton setBackgroundColor:[UIColor clearColor]]; |
| 109 [_activationButton setInkColor:ui_util::InkColor()]; | 109 [_activationButton setInkColor:ui_util::InkColor()]; |
| 110 [_activationButton setCornerRadius:2]; | 110 [_activationButton setCornerRadius:2]; |
| 111 [_activationButton setBorderWidth:1]; | 111 [_activationButton setBorderWidth:1]; |
| 112 [_activationButton setBorderColor:ui_util::BorderColor()]; | 112 [_activationButton setBorderColor:ui_util::BorderColor()]; |
| 113 [self addSubview:_activationButton]; | 113 [self addSubview:_activationButton]; |
| 114 [self bringSubviewToFront:_activationButton]; | 114 [self bringSubviewToFront:_activationButton]; |
| 115 _buttonTopConstraint.reset([[[_activationButton topAnchor] | 115 _buttonTopConstraint.reset([[_activationButton topAnchor] |
| 116 constraintEqualToAnchor:[self topAnchor]] retain]); | 116 constraintEqualToAnchor:[self topAnchor]]); |
| 117 _buttonLeftConstraint.reset([[[_activationButton leftAnchor] | 117 _buttonLeftConstraint.reset([[_activationButton leftAnchor] |
| 118 constraintEqualToAnchor:[self leftAnchor]] retain]); | 118 constraintEqualToAnchor:[self leftAnchor]]); |
| 119 _buttonWidthConstraint.reset([[[_activationButton widthAnchor] | 119 _buttonWidthConstraint.reset( |
| 120 constraintEqualToConstant:0] retain]); | 120 [[_activationButton widthAnchor] constraintEqualToConstant:0]); |
| 121 _buttonHeightConstraint.reset([[[_activationButton heightAnchor] | 121 _buttonHeightConstraint.reset( |
| 122 constraintEqualToConstant:0] retain]); | 122 [[_activationButton heightAnchor] constraintEqualToConstant:0]); |
| 123 [NSLayoutConstraint activateConstraints:@[ | 123 [NSLayoutConstraint activateConstraints:@[ |
| 124 _buttonTopConstraint, _buttonLeftConstraint, _buttonWidthConstraint, | 124 _buttonTopConstraint, _buttonLeftConstraint, _buttonWidthConstraint, |
| 125 _buttonHeightConstraint | 125 _buttonHeightConstraint |
| 126 ]]; | 126 ]]; |
| 127 | 127 |
| 128 // Add two spaces before and after the button label to add padding to the | 128 // Add two spaces before and after the button label to add padding to the |
| 129 // button. | 129 // button. |
| 130 buttonText = [NSString stringWithFormat:@" %@ ", _buttonString.get()]; | 130 buttonText = [NSString stringWithFormat:@" %@ ", _buttonString.get()]; |
| 131 // Replace spaces by non breaking spaces to prevent buttons from wrapping. | 131 // Replace spaces by non breaking spaces to prevent buttons from wrapping. |
| 132 buttonText = [buttonText stringByReplacingOccurrencesOfString:@" " | 132 buttonText = [buttonText stringByReplacingOccurrencesOfString:@" " |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 [_buttonTopConstraint setConstant:buttonFrame.origin.y]; | 226 [_buttonTopConstraint setConstant:buttonFrame.origin.y]; |
| 227 [_buttonLeftConstraint setConstant:buttonFrame.origin.x]; | 227 [_buttonLeftConstraint setConstant:buttonFrame.origin.x]; |
| 228 [_buttonWidthConstraint setConstant:buttonFrame.size.width]; | 228 [_buttonWidthConstraint setConstant:buttonFrame.size.width]; |
| 229 [_buttonHeightConstraint setConstant:buttonFrame.size.height]; | 229 [_buttonHeightConstraint setConstant:buttonFrame.size.height]; |
| 230 } | 230 } |
| 231 } | 231 } |
| 232 | 232 |
| 233 - (BOOL)textView:(UITextView*)textView | 233 - (BOOL)textView:(UITextView*)textView |
| 234 shouldInteractWithURL:(NSURL*)URL | 234 shouldInteractWithURL:(NSURL*)URL |
| 235 inRange:(NSRange)characterRange { | 235 inRange:(NSRange)characterRange { |
| 236 _linkBlock.get()(); | 236 if (_linkBlock) |
| 237 _linkBlock(); |
| 237 return NO; | 238 return NO; |
| 238 } | 239 } |
| 239 | 240 |
| 240 - (void)buttonPressed:(id)sender { | 241 - (void)buttonPressed:(id)sender { |
| 241 _buttonBlock.get()(); | 242 if (_buttonBlock) |
| 243 _buttonBlock(); |
| 242 } | 244 } |
| 243 | 245 |
| 244 - (CGSize)intrinsicContentSize { | 246 - (CGSize)intrinsicContentSize { |
| 245 return [self sizeThatFits:CGSizeMake(_currentWidth, CGFLOAT_MAX)]; | 247 return [self sizeThatFits:CGSizeMake(_currentWidth, CGFLOAT_MAX)]; |
| 246 } | 248 } |
| 247 | 249 |
| 248 - (CGSize)sizeThatFits:(CGSize)size { | 250 - (CGSize)sizeThatFits:(CGSize)size { |
| 249 if (![_attributedText length]) | 251 if (![_attributedText length]) |
| 250 return CGSizeMake(size.width, | 252 return CGSizeMake(size.width, |
| 251 MIN(_insets.top + _insets.bottom, size.height)); | 253 MIN(_insets.top + _insets.bottom, size.height)); |
| 252 | 254 |
| 253 // -sizeThatFits: doesn't behaves properly with UITextView. | 255 // -sizeThatFits: doesn't behaves properly with UITextView. |
| 254 // Therefore, we need to measure text size using | 256 // Therefore, we need to measure text size using |
| 255 // -boundingRectWithSize:options:context:. | 257 // -boundingRectWithSize:options:context:. |
| 256 CGSize constraints = | 258 CGSize constraints = |
| 257 CGSizeMake(size.width - _insets.left - _insets.right, CGFLOAT_MAX); | 259 CGSizeMake(size.width - _insets.left - _insets.right, CGFLOAT_MAX); |
| 258 CGRect bounding = [_attributedText | 260 CGRect bounding = [_attributedText |
| 259 boundingRectWithSize:constraints | 261 boundingRectWithSize:constraints |
| 260 options:static_cast<NSStringDrawingOptions>( | 262 options:static_cast<NSStringDrawingOptions>( |
| 261 NSStringDrawingUsesLineFragmentOrigin | | 263 NSStringDrawingUsesLineFragmentOrigin | |
| 262 NSStringDrawingUsesFontLeading) | 264 NSStringDrawingUsesFontLeading) |
| 263 context:nil]; | 265 context:nil]; |
| 264 return CGSizeMake( | 266 return CGSizeMake( |
| 265 size.width, | 267 size.width, |
| 266 MIN(bounding.size.height + _insets.top + _insets.bottom, size.height)); | 268 MIN(bounding.size.height + _insets.top + _insets.bottom, size.height)); |
| 267 } | 269 } |
| 268 | 270 |
| 269 @end | 271 @end |
| OLD | NEW |