OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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/ui/ntp/most_visited_cell.h" |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #import "base/ios/weak_nsobject.h" |
| 10 #include "base/mac/bind_objc_block.h" |
| 11 #import "base/mac/scoped_nsobject.h" |
| 12 #include "base/memory/ref_counted_memory.h" |
| 13 #include "base/strings/sys_string_conversions.h" |
| 14 #include "base/task/cancelable_task_tracker.h" |
| 15 #include "components/favicon/core/fallback_url_util.h" |
| 16 #include "components/favicon/core/large_icon_service.h" |
| 17 #include "components/favicon_base/fallback_icon_style.h" |
| 18 #include "components/favicon_base/favicon_types.h" |
| 19 #include "components/history/core/browser/top_sites.h" |
| 20 #include "components/suggestions/suggestions_service.h" |
| 21 #import "ios/chrome/browser/favicon/favicon_loader.h" |
| 22 #include "ios/chrome/browser/favicon/favicon_service_factory.h" |
| 23 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h" |
| 24 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_cache_factory.h" |
| 25 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" |
| 26 #include "ios/chrome/browser/favicon/large_icon_cache.h" |
| 27 #include "ios/chrome/browser/history/top_sites_factory.h" |
| 28 #include "ios/chrome/browser/suggestions/suggestions_service_factory.h" |
| 29 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 30 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat
erialPalettes.h" |
| 31 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" |
| 32 #include "skia/ext/skia_utils_ios.h" |
| 33 |
| 34 const CGFloat kFaviconSize = 48; |
| 35 const CGFloat kFaviconMinSize = 32; |
| 36 const CGFloat kImageViewBackgroundColor = 0.941; |
| 37 const CGFloat kImageViewCornerRadius = 3; |
| 38 const NSInteger kLabelNumLines = 2; |
| 39 const CGFloat kLabelTextColor = 0.314; |
| 40 const CGFloat kMaximumWidth = 73; |
| 41 const CGFloat kMaximumHeight = 100; |
| 42 |
| 43 @interface MostVisitedCell () { |
| 44 // Backs property with the same name. |
| 45 GURL _URL; |
| 46 // Weak reference to the relevant BrowserState. |
| 47 ios::ChromeBrowserState* _browserState; |
| 48 // Backs property with the same name. |
| 49 ntp_tiles::metrics::MostVisitedTileType _tileType; |
| 50 |
| 51 base::scoped_nsobject<UILabel> _label; |
| 52 base::scoped_nsobject<UILabel> _noIconLabel; |
| 53 base::scoped_nsobject<UIImageView> _imageView; |
| 54 // Used to cancel tasks for the LargeIconService. |
| 55 base::CancelableTaskTracker _cancelable_task_tracker; |
| 56 } |
| 57 // Set the background color and center the first letter of the site title (or |
| 58 // domain if the title is a url). |
| 59 - (void)updateIconLabelWithColor:(UIColor*)textColor |
| 60 backgroundColor:(UIColor*)backgroundColor |
| 61 isDefaultBackgroundColor:(BOOL)isDefaultBackgroundColor; |
| 62 // Set icon of top site. |
| 63 - (void)setImage:(UIImage*)image; |
| 64 @end |
| 65 |
| 66 @implementation MostVisitedCell |
| 67 |
| 68 @synthesize URL = _URL; |
| 69 @synthesize browserState = _browserState; |
| 70 @synthesize tileType = _tileType; |
| 71 |
| 72 - (instancetype)initWithFrame:(CGRect)frame { |
| 73 self = [super initWithFrame:frame]; |
| 74 if (!self) { |
| 75 return nil; |
| 76 } |
| 77 _label.reset([[UILabel alloc] initWithFrame:CGRectZero]); |
| 78 [_label setTextColor:[UIColor colorWithWhite:kLabelTextColor alpha:1.0]]; |
| 79 [_label setBackgroundColor:[UIColor clearColor]]; |
| 80 [_label setFont:[MDCTypography captionFont]]; |
| 81 [_label setTextAlignment:NSTextAlignmentCenter]; |
| 82 CGSize maxSize = [self.class maximumSize]; |
| 83 [_label setPreferredMaxLayoutWidth:maxSize.width]; |
| 84 [_label setNumberOfLines:kLabelNumLines]; |
| 85 |
| 86 _noIconLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); |
| 87 [_noIconLabel setBackgroundColor:[UIColor clearColor]]; |
| 88 [_noIconLabel setFont:[MDCTypography headlineFont]]; |
| 89 [_noIconLabel setTextAlignment:NSTextAlignmentCenter]; |
| 90 |
| 91 _imageView.reset([[UIImageView alloc] initWithFrame:CGRectZero]); |
| 92 [_imageView layer].cornerRadius = kImageViewCornerRadius; |
| 93 [_imageView setClipsToBounds:YES]; |
| 94 [self addSubview:_imageView]; |
| 95 [self addSubview:_label]; |
| 96 [self addSubview:_noIconLabel]; |
| 97 |
| 98 [_noIconLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 99 [_imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 100 [_label setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 101 |
| 102 NSDictionary* views = |
| 103 @{ @"label" : _label, |
| 104 @"image" : _imageView, |
| 105 @"noIcon" : _noIconLabel }; |
| 106 NSArray* constraints = @[ |
| 107 @"V:|[image(==iconSize)]-10-[label]", @"V:[noIcon(==iconSize)]", |
| 108 @"H:[image(==iconSize)]", @"H:|[label]|", @"H:|[noIcon]|" |
| 109 ]; |
| 110 ApplyVisualConstraintsWithMetrics(constraints, views, |
| 111 @{ @"iconSize" : @(kFaviconSize) }); |
| 112 AddSameCenterXConstraint(self, _imageView); |
| 113 AddSameCenterXConstraint(self, _noIconLabel); |
| 114 |
| 115 [self prepareForReuse]; |
| 116 return self; |
| 117 } |
| 118 |
| 119 - (void)prepareForReuse { |
| 120 [super prepareForReuse]; |
| 121 [self setImage:nil]; |
| 122 [self setText:nil]; |
| 123 // TODO(crbug.com/495600): -stepToVerifyAccessibilityOnCurrentScreen does not |
| 124 // honor -setIsAccessibilityElement and setAccessibilityElementsHidden for |
| 125 // UICollectionViewCell's, so setting the label to a single space string to |
| 126 // pass tests. This string will not be read by screen readers. |
| 127 [_label setText:@" "]; |
| 128 [self setURL:GURL()]; |
| 129 [_imageView |
| 130 setBackgroundColor:[UIColor colorWithWhite:kImageViewBackgroundColor |
| 131 alpha:1.0]]; |
| 132 [_noIconLabel setText:nil]; |
| 133 } |
| 134 |
| 135 #pragma mark - Public Setters |
| 136 |
| 137 - (void)setText:(NSString*)text { |
| 138 [_label setText:text]; |
| 139 [self setAccessibilityLabel:text]; |
| 140 [self setIsAccessibilityElement:text != nil]; |
| 141 [self setAccessibilityElementsHidden:text == nil]; |
| 142 [self setUserInteractionEnabled:YES]; |
| 143 } |
| 144 |
| 145 - (void)showPlaceholder { |
| 146 [_imageView setBackgroundColor:[[MDCPalette greyPalette] tint50]]; |
| 147 } |
| 148 |
| 149 - (void)setupWithURL:(GURL)URL |
| 150 title:(NSString*)title |
| 151 browserState:(ios::ChromeBrowserState*)browserState { |
| 152 _browserState = browserState; |
| 153 _tileType = ntp_tiles::metrics::NONE; |
| 154 [self setText:title]; |
| 155 [self setURL:URL]; |
| 156 base::WeakNSObject<MostVisitedCell> weakSelf(self); |
| 157 |
| 158 void (^faviconBlock)(const favicon_base::LargeIconResult&) = |
| 159 ^(const favicon_base::LargeIconResult& result) { |
| 160 base::scoped_nsobject<MostVisitedCell> strongSelf([weakSelf retain]); |
| 161 if (!strongSelf) |
| 162 return; |
| 163 |
| 164 if (URL == [strongSelf URL]) { // Tile has not been reused. |
| 165 if (result.bitmap.is_valid()) { |
| 166 scoped_refptr<base::RefCountedMemory> data = |
| 167 result.bitmap.bitmap_data.get(); |
| 168 UIImage* favicon = |
| 169 [UIImage imageWithData:[NSData dataWithBytes:data->front() |
| 170 length:data->size()] |
| 171 scale:[UIScreen mainScreen].scale]; |
| 172 [strongSelf setImage:favicon]; |
| 173 } else if (result.fallback_icon_style) { |
| 174 UIColor* backgroundColor = skia::UIColorFromSkColor( |
| 175 result.fallback_icon_style->background_color); |
| 176 UIColor* textColor = skia::UIColorFromSkColor( |
| 177 result.fallback_icon_style->text_color); |
| 178 [strongSelf updateIconLabelWithColor:textColor |
| 179 backgroundColor:backgroundColor |
| 180 isDefaultBackgroundColor:result.fallback_icon_style-> |
| 181 is_default_background_color]; |
| 182 } |
| 183 } |
| 184 |
| 185 if (result.bitmap.is_valid() || result.fallback_icon_style) { |
| 186 IOSChromeLargeIconCacheFactory::GetForBrowserState( |
| 187 [strongSelf browserState]) |
| 188 ->SetCachedResult(URL, result); |
| 189 } |
| 190 }; |
| 191 |
| 192 LargeIconCache* cache = |
| 193 IOSChromeLargeIconCacheFactory::GetForBrowserState(self.browserState); |
| 194 std::unique_ptr<favicon_base::LargeIconResult> cached_result = |
| 195 cache->GetCachedResult(URL); |
| 196 if (cached_result) { |
| 197 faviconBlock(*cached_result); |
| 198 } |
| 199 |
| 200 // Always call LargeIconService in case the favicon was updated. |
| 201 favicon::LargeIconService* large_icon_service = |
| 202 IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState); |
| 203 CGFloat faviconSize = [UIScreen mainScreen].scale * kFaviconSize; |
| 204 CGFloat faviconMinSize = [UIScreen mainScreen].scale * kFaviconMinSize; |
| 205 large_icon_service->GetLargeIconOrFallbackStyle( |
| 206 URL, faviconMinSize, faviconSize, base::BindBlock(faviconBlock), |
| 207 &_cancelable_task_tracker); |
| 208 } |
| 209 |
| 210 - (void)removePlaceholderImage { |
| 211 [_imageView setBackgroundColor:nil]; |
| 212 [self setUserInteractionEnabled:NO]; |
| 213 } |
| 214 |
| 215 #pragma mark - Class methods |
| 216 |
| 217 + (CGSize)maximumSize { |
| 218 return CGSizeMake(kMaximumWidth, kMaximumHeight); |
| 219 } |
| 220 |
| 221 #pragma mark - Private methods |
| 222 |
| 223 - (void)updateIconLabelWithColor:(UIColor*)textColor |
| 224 backgroundColor:(UIColor*)backgroundColor |
| 225 isDefaultBackgroundColor:(BOOL)isDefaultBackgroundColor { |
| 226 [self setImage:nil]; |
| 227 [_noIconLabel |
| 228 setText:base::SysUTF16ToNSString(favicon::GetFallbackIconText(_URL))]; |
| 229 [_noIconLabel setTextColor:textColor]; |
| 230 [_imageView setBackgroundColor:backgroundColor]; |
| 231 _tileType = isDefaultBackgroundColor ? ntp_tiles::metrics::ICON_DEFAULT |
| 232 : ntp_tiles::metrics::ICON_COLOR; |
| 233 } |
| 234 |
| 235 - (void)setImage:(UIImage*)image { |
| 236 [_imageView setBackgroundColor:nil]; |
| 237 [_noIconLabel setText:nil]; |
| 238 [_imageView setImage:image]; |
| 239 _tileType = ntp_tiles::metrics::ICON_REAL; |
| 240 } |
| 241 |
| 242 @end |
OLD | NEW |