Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_article_item.mm

Issue 2770113006: Add no-image image in ContentSuggestions (Closed)
Patch Set: Fix tests Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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/browser/ui/content_suggestions/cells/content_suggestions_art icle_item.h" 5 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_art icle_item.h"
6 6
7 #include "base/time/time.h" 7 #include "base/time/time.h"
8 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" 8 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
9 #import "ios/chrome/browser/ui/uikit_ui_util.h" 9 #import "ios/chrome/browser/ui/uikit_ui_util.h"
10 #import "ios/chrome/browser/ui/util/i18n_string.h" 10 #import "ios/chrome/browser/ui/util/i18n_string.h"
11 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
11 #import "ios/third_party/material_components_ios/src/components/Typography/src/M aterialTypography.h" 12 #import "ios/third_party/material_components_ios/src/components/Typography/src/M aterialTypography.h"
12 #include "url/gurl.h" 13 #include "url/gurl.h"
13 14
14 #if !defined(__has_feature) || !__has_feature(objc_arc) 15 #if !defined(__has_feature) || !__has_feature(objc_arc)
15 #error "This file requires ARC support." 16 #error "This file requires ARC support."
16 #endif 17 #endif
17 18
18 namespace { 19 namespace {
19 const CGFloat kImageSize = 72; 20 const CGFloat kImageSize = 72;
20 // When updating this, make sure to update |layoutSubviews|. 21 // When updating this, make sure to update |layoutSubviews|.
21 const CGFloat kStandardSpacing = 16; 22 const CGFloat kStandardSpacing = 16;
23 // Size of the icon displayed when there is not image.
24 const CGFloat kIconSize = 24;
25 // Name of the icon displayed when there is not image.
26 NSString* const kNoImageIconName = @"content_suggestions_no_image";
27 // No image icon percentage of white.
28 const CGFloat kNoImageIconWhite = 0.38;
29 // No image background percentage of white.
30 const CGFloat kNoImageBackgroundWhite = 0.95;
31 // Duration of the animation to display the image for the article.
32 const CGFloat kAnimationDuration = 0.3;
22 } 33 }
23 34
24 @interface ContentSuggestionsArticleItem () 35 @interface ContentSuggestionsArticleItem ()
25 36
26 @property(nonatomic, copy) NSString* subtitle; 37 @property(nonatomic, copy) NSString* subtitle;
27 // Used to check if the image has already been fetched. There is no way to 38 // Used to check if the image has already been fetched. There is no way to
28 // discriminate between failed image download and nonexitent image. The article 39 // discriminate between failed image download and nonexitent image. The article
29 // tries to download the image only once. 40 // tries to download the image only once.
30 @property(nonatomic, assign) BOOL imageFetched; 41 @property(nonatomic, assign) BOOL imageFetched;
31 42
(...skipping 18 matching lines...) Expand all
50 subtitle:(NSString*)subtitle 61 subtitle:(NSString*)subtitle
51 delegate:(id<ContentSuggestionsArticleItemDelegate>)delegate 62 delegate:(id<ContentSuggestionsArticleItemDelegate>)delegate
52 url:(const GURL&)url { 63 url:(const GURL&)url {
53 self = [super initWithType:type]; 64 self = [super initWithType:type];
54 if (self) { 65 if (self) {
55 self.cellClass = [ContentSuggestionsArticleCell class]; 66 self.cellClass = [ContentSuggestionsArticleCell class];
56 _title = [title copy]; 67 _title = [title copy];
57 _subtitle = [subtitle copy]; 68 _subtitle = [subtitle copy];
58 _articleURL = url; 69 _articleURL = url;
59 _delegate = delegate; 70 _delegate = delegate;
60 _image = [self emptyImageBackground];
61 } 71 }
62 return self; 72 return self;
63 } 73 }
64 74
65 - (void)configureCell:(ContentSuggestionsArticleCell*)cell { 75 - (void)configureCell:(ContentSuggestionsArticleCell*)cell {
66 [super configureCell:cell]; 76 [super configureCell:cell];
67 if (!self.imageFetched) { 77 if (!self.imageFetched) {
68 self.imageFetched = YES; 78 self.imageFetched = YES;
69 // Fetch the image. During the fetch the cell's image should still be set. 79 // Fetch the image. During the fetch the cell's image should still be set.
70 [self.delegate loadImageForArticleItem:self]; 80 [self.delegate loadImageForArticleItem:self];
71 } 81 }
72 cell.titleLabel.text = self.title; 82 cell.titleLabel.text = self.title;
73 cell.subtitleLabel.text = self.subtitle; 83 cell.subtitleLabel.text = self.subtitle;
74 cell.imageView.image = self.image; 84 [cell setContentImage:self.image];
75 [cell setPublisherName:self.publisher date:self.publishDate]; 85 [cell setPublisherName:self.publisher date:self.publishDate];
76 } 86 }
77 87
78 #pragma mark - Private
79
80 - (UIImage*)emptyImageBackground {
81 // TODO(crbug.com/698171): Remove this function once we have real background
82 // image.
83 UIColor* color = [UIColor lightGrayColor];
84 CGRect rect = CGRectMake(0, 0, 1, 1);
85 UIGraphicsBeginImageContext(rect.size);
86 [color setFill];
87 UIRectFill(rect);
88 UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
89 UIGraphicsEndImageContext();
90 return image;
91 }
92
93 @end 88 @end
94 89
95 #pragma mark - ContentSuggestionsArticleCell 90 #pragma mark - ContentSuggestionsArticleCell
96 91
97 @interface ContentSuggestionsArticleCell () 92 @interface ContentSuggestionsArticleCell ()
98 93
99 @property(nonatomic, strong) UILabel* publisherLabel; 94 @property(nonatomic, strong) UILabel* publisherLabel;
95 // Contains the no-image icon or the image.
96 @property(nonatomic, strong) UIView* imageContainer;
97 // The no-image icon displayed when there is no image.
98 @property(nonatomic, strong) UIImageView* noImageIcon;
99 // Displays the image associated with this article. It is added to the
100 // imageContainer only if there is an image to display, hiding the no-image
101 // icon.
102 @property(nonatomic, strong) UIImageView* contentImageView;
100 103
101 // Applies the constraints on the elements. Called in the init. 104 // Applies the constraints on the elements. Called in the init.
102 - (void)applyConstraints; 105 - (void)applyConstraints;
103 106
104 @end 107 @end
105 108
106 @implementation ContentSuggestionsArticleCell 109 @implementation ContentSuggestionsArticleCell
107 110
108 @synthesize titleLabel = _titleLabel; 111 @synthesize titleLabel = _titleLabel;
109 @synthesize subtitleLabel = _subtitleLabel; 112 @synthesize subtitleLabel = _subtitleLabel;
110 @synthesize imageView = _imageView; 113 @synthesize imageContainer = _imageContainer;
114 @synthesize noImageIcon = _noImageIcon;
111 @synthesize publisherLabel = _publisherLabel; 115 @synthesize publisherLabel = _publisherLabel;
116 @synthesize contentImageView = _contentImageView;
112 117
113 - (instancetype)initWithFrame:(CGRect)frame { 118 - (instancetype)initWithFrame:(CGRect)frame {
114 self = [super initWithFrame:frame]; 119 self = [super initWithFrame:frame];
115 if (self) { 120 if (self) {
116 _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 121 _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
117 _subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 122 _subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
118 _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; 123 _imageContainer = [[UIView alloc] initWithFrame:CGRectZero];
124 _noImageIcon = [[UIImageView alloc] initWithFrame:CGRectZero];
119 _publisherLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 125 _publisherLabel = [[UILabel alloc] initWithFrame:CGRectZero];
120 126
121 _titleLabel.numberOfLines = 2; 127 _titleLabel.numberOfLines = 2;
122 _subtitleLabel.numberOfLines = 2; 128 _subtitleLabel.numberOfLines = 2;
123 [_subtitleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh 129 [_subtitleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh
124 forAxis:UILayoutConstraintAxisVertical]; 130 forAxis:UILayoutConstraintAxisVertical];
125 [_titleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh 131 [_titleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh
126 forAxis:UILayoutConstraintAxisVertical]; 132 forAxis:UILayoutConstraintAxisVertical];
127 _imageView.contentMode = UIViewContentModeScaleAspectFill;
128 _imageView.clipsToBounds = YES;
129 133
130 _imageView.translatesAutoresizingMaskIntoConstraints = NO; 134 _imageContainer.translatesAutoresizingMaskIntoConstraints = NO;
135 _noImageIcon.translatesAutoresizingMaskIntoConstraints = NO;
131 _titleLabel.translatesAutoresizingMaskIntoConstraints = NO; 136 _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
132 _subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; 137 _subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
133 _publisherLabel.translatesAutoresizingMaskIntoConstraints = NO; 138 _publisherLabel.translatesAutoresizingMaskIntoConstraints = NO;
134 139
135 [self.contentView addSubview:_imageView]; 140 [self.contentView addSubview:_imageContainer];
136 [self.contentView addSubview:_titleLabel]; 141 [self.contentView addSubview:_titleLabel];
137 [self.contentView addSubview:_subtitleLabel]; 142 [self.contentView addSubview:_subtitleLabel];
138 [self.contentView addSubview:_publisherLabel]; 143 [self.contentView addSubview:_publisherLabel];
139 144
145 [_imageContainer addSubview:_noImageIcon];
146
147 _imageContainer.backgroundColor =
148 [UIColor colorWithWhite:kNoImageBackgroundWhite alpha:1];
149 _noImageIcon.image = [[UIImage imageNamed:kNoImageIconName]
150 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
151 [_noImageIcon
152 setTintColor:[UIColor colorWithWhite:kNoImageIconWhite alpha:1]];
153
140 _titleLabel.font = [MDCTypography subheadFont]; 154 _titleLabel.font = [MDCTypography subheadFont];
141 _subtitleLabel.font = [MDCTypography body1Font]; 155 _subtitleLabel.font = [MDCTypography body1Font];
142 _publisherLabel.font = [MDCTypography captionFont]; 156 _publisherLabel.font = [MDCTypography captionFont];
143 157
144 _subtitleLabel.textColor = [[MDCPalette greyPalette] tint700]; 158 _subtitleLabel.textColor = [[MDCPalette greyPalette] tint700];
145 _publisherLabel.textColor = [[MDCPalette greyPalette] tint700]; 159 _publisherLabel.textColor = [[MDCPalette greyPalette] tint700];
146 160
147 [self applyConstraints]; 161 [self applyConstraints];
148 } 162 }
149 return self; 163 return self;
150 } 164 }
151 165
166 - (void)setContentImage:(UIImage*)image {
167 if (!image)
168 return;
169 self.contentImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
170 self.contentImageView.translatesAutoresizingMaskIntoConstraints = NO;
171 self.contentImageView.contentMode = UIViewContentModeScaleAspectFill;
172 self.contentImageView.clipsToBounds = YES;
173 self.contentImageView.image = image;
174
175 self.contentImageView.alpha = 0;
176 [self.imageContainer addSubview:self.contentImageView];
177 AddSameSizeConstraint(self.contentImageView, self.imageContainer);
178
179 [UIView animateWithDuration:kAnimationDuration
180 animations:^{
181 self.contentImageView.alpha = 1;
182 }];
183 }
184
152 - (void)setPublisherName:(NSString*)publisherName date:(base::Time)publishDate { 185 - (void)setPublisherName:(NSString*)publisherName date:(base::Time)publishDate {
153 NSDate* date = [NSDate dateWithTimeIntervalSince1970:publishDate.ToDoubleT()]; 186 NSDate* date = [NSDate dateWithTimeIntervalSince1970:publishDate.ToDoubleT()];
154 NSString* dateString = 187 NSString* dateString =
155 [NSDateFormatter localizedStringFromDate:date 188 [NSDateFormatter localizedStringFromDate:date
156 dateStyle:NSDateFormatterMediumStyle 189 dateStyle:NSDateFormatterMediumStyle
157 timeStyle:NSDateFormatterNoStyle]; 190 timeStyle:NSDateFormatterNoStyle];
158 191
159 self.publisherLabel.text = AdjustStringForLocaleDirection( 192 self.publisherLabel.text = AdjustStringForLocaleDirection(
160 [NSString stringWithFormat:@"%@ - %@.", publisherName, dateString]); 193 [NSString stringWithFormat:@"%@ - %@.", publisherName, dateString]);
161 } 194 }
162 195
196 - (void)prepareForReuse {
197 [self.contentImageView removeFromSuperview];
198 }
199
163 #pragma mark - UIView 200 #pragma mark - UIView
164 201
165 // Implements -layoutSubviews as per instructions in documentation for 202 // Implements -layoutSubviews as per instructions in documentation for
166 // +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:]. 203 // +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:].
167 - (void)layoutSubviews { 204 - (void)layoutSubviews {
168 [super layoutSubviews]; 205 [super layoutSubviews];
169 206
170 // Adjust the text label preferredMaxLayoutWidth when the parent's width 207 // Adjust the text label preferredMaxLayoutWidth when the parent's width
171 // changes, for instance on screen rotation. 208 // changes, for instance on screen rotation.
172 CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds); 209 CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds);
173 210
174 self.titleLabel.preferredMaxLayoutWidth = 211 self.titleLabel.preferredMaxLayoutWidth =
175 parentWidth - kImageSize - 3 * kStandardSpacing; 212 parentWidth - kImageSize - 3 * kStandardSpacing;
176 self.subtitleLabel.preferredMaxLayoutWidth = 213 self.subtitleLabel.preferredMaxLayoutWidth =
177 parentWidth - kImageSize - 3 * kStandardSpacing; 214 parentWidth - kImageSize - 3 * kStandardSpacing;
178 215
179 // Re-layout with the new preferred width to allow the label to adjust its 216 // Re-layout with the new preferred width to allow the label to adjust its
180 // height. 217 // height.
181 [super layoutSubviews]; 218 [super layoutSubviews];
182 } 219 }
183 220
184 #pragma mark - Private 221 #pragma mark - Private
185 222
186 - (void)applyConstraints { 223 - (void)applyConstraints {
187 [NSLayoutConstraint activateConstraints:@[ 224 [NSLayoutConstraint activateConstraints:@[
188 [_imageView.widthAnchor constraintEqualToConstant:kImageSize], 225 [_imageContainer.widthAnchor constraintEqualToConstant:kImageSize],
189 [_imageView.heightAnchor constraintEqualToAnchor:_imageView.widthAnchor], 226 [_imageContainer.heightAnchor
190 [_imageView.topAnchor constraintEqualToAnchor:_titleLabel.topAnchor], 227 constraintEqualToAnchor:_imageContainer.widthAnchor],
228 [_imageContainer.topAnchor constraintEqualToAnchor:_titleLabel.topAnchor],
191 [_publisherLabel.topAnchor 229 [_publisherLabel.topAnchor
192 constraintGreaterThanOrEqualToAnchor:_imageView.bottomAnchor 230 constraintGreaterThanOrEqualToAnchor:_imageContainer.bottomAnchor
193 constant:kStandardSpacing], 231 constant:kStandardSpacing],
194 [_publisherLabel.topAnchor 232 [_publisherLabel.topAnchor
195 constraintGreaterThanOrEqualToAnchor:_subtitleLabel.bottomAnchor 233 constraintGreaterThanOrEqualToAnchor:_subtitleLabel.bottomAnchor
196 constant:kStandardSpacing], 234 constant:kStandardSpacing],
235
236 // No image icon.
237 [_noImageIcon.centerXAnchor
238 constraintEqualToAnchor:_imageContainer.centerXAnchor],
239 [_noImageIcon.centerYAnchor
240 constraintEqualToAnchor:_imageContainer.centerYAnchor],
241 [_noImageIcon.widthAnchor constraintEqualToConstant:kIconSize],
242 [_noImageIcon.heightAnchor constraintEqualToAnchor:_noImageIcon.widthAnchor]
197 ]]; 243 ]];
198 244
199 ApplyVisualConstraintsWithMetrics( 245 ApplyVisualConstraintsWithMetrics(
200 @[ 246 @[
201 @"H:|-(space)-[title]-(space)-[image]-(space)-|", 247 @"H:|-(space)-[title]-(space)-[image]-(space)-|",
202 @"H:|-(space)-[text]-(space)-[image]", 248 @"H:|-(space)-[text]-(space)-[image]",
203 @"V:|-(space)-[title]-[text]", 249 @"V:|-(space)-[title]-[text]",
204 @"H:|-(space)-[publish]-(space)-|", 250 @"H:|-(space)-[publish]-(space)-|",
205 @"V:[publish]-|", 251 @"V:[publish]-|",
206 ], 252 ],
207 @{ 253 @{
208 @"image" : _imageView, 254 @"image" : _imageContainer,
209 @"title" : _titleLabel, 255 @"title" : _titleLabel,
210 @"text" : _subtitleLabel, 256 @"text" : _subtitleLabel,
211 @"publish" : _publisherLabel, 257 @"publish" : _publisherLabel,
212 }, 258 },
213 @{ @"space" : @(kStandardSpacing) }); 259 @{ @"space" : @(kStandardSpacing) });
214 } 260 }
215 261
216 @end 262 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698