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

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

Issue 2865183003: Use the same design for all suggestions (Closed)
Patch Set: Address comments Created 3 years, 7 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_art icle_item.h"
6
7 #include "base/time/time.h"
8 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
9 #import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
10 #import "ios/chrome/browser/ui/favicon/favicon_view.h"
11 #import "ios/chrome/browser/ui/uikit_ui_util.h"
12 #import "ios/chrome/browser/ui/util/i18n_string.h"
13 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
14 #import "ios/third_party/material_components_ios/src/components/Typography/src/M aterialTypography.h"
15 #include "url/gurl.h"
16
17 #if !defined(__has_feature) || !__has_feature(objc_arc)
18 #error "This file requires ARC support."
19 #endif
20
21 namespace {
22 const CGFloat kImageSize = 72;
23 const CGFloat kStandardSpacing = 16;
24 const CGFloat kSmallSpacing = 8;
25
26 // Size of the favicon view.
27 const CGFloat kFaviconSize = 16;
28 // Size of the icon displayed when there is not image.
29 const CGFloat kIconSize = 24;
30 // Name of the icon displayed when there is not image.
31 NSString* const kNoImageIconName = @"content_suggestions_no_image";
32 // No image icon percentage of white.
33 const CGFloat kNoImageIconWhite = 0.38;
34 // No image background percentage of white.
35 const CGFloat kNoImageBackgroundWhite = 0.95;
36 // Duration of the animation to display the image for the article.
37 const CGFloat kAnimationDuration = 0.3;
38 }
39
40 @interface ContentSuggestionsArticleItem ()
41
42 @property(nonatomic, copy) NSString* subtitle;
43 // Used to check if the image has already been fetched. There is no way to
44 // discriminate between failed image download and nonexitent image. The article
45 // tries to download the image only once.
46 @property(nonatomic, assign) BOOL imageFetched;
47
48 @end
49
50 #pragma mark - ContentSuggestionsArticleItem
51
52 @implementation ContentSuggestionsArticleItem
53
54 @synthesize title = _title;
55 @synthesize subtitle = _subtitle;
56 @synthesize image = _image;
57 @synthesize articleURL = _articleURL;
58 @synthesize publisher = _publisher;
59 @synthesize publishDate = _publishDate;
60 @synthesize suggestionIdentifier = _suggestionIdentifier;
61 @synthesize delegate = _delegate;
62 @synthesize imageFetched = _imageFetched;
63 @synthesize attributes = _attributes;
64
65 - (instancetype)initWithType:(NSInteger)type
66 title:(NSString*)title
67 subtitle:(NSString*)subtitle
68 delegate:(id<ContentSuggestionsArticleItemDelegate>)delegate
69 url:(const GURL&)url {
70 self = [super initWithType:type];
71 if (self) {
72 self.cellClass = [ContentSuggestionsArticleCell class];
73 _title = [title copy];
74 _subtitle = [subtitle copy];
75 _articleURL = url;
76 _delegate = delegate;
77 }
78 return self;
79 }
80
81 - (void)configureCell:(ContentSuggestionsArticleCell*)cell {
82 [super configureCell:cell];
83 if (!self.imageFetched) {
84 self.imageFetched = YES;
85 // Fetch the image. During the fetch the cell's image should still be set.
86 [self.delegate loadImageForArticleItem:self];
87 }
88 if (self.attributes)
89 [cell.faviconView configureWithAttributes:self.attributes];
90 cell.titleLabel.text = self.title;
91 cell.subtitleLabel.text = self.subtitle;
92 [cell setContentImage:self.image];
93 [cell setPublisherName:self.publisher date:self.publishDate];
94 }
95
96 @end
97
98 #pragma mark - ContentSuggestionsArticleCell
99
100 @interface ContentSuggestionsArticleCell ()
101
102 @property(nonatomic, strong) UILabel* publisherLabel;
103 // Contains the no-image icon or the image.
104 @property(nonatomic, strong) UIView* imageContainer;
105 // The no-image icon displayed when there is no image.
106 @property(nonatomic, strong) UIImageView* noImageIcon;
107 // Displays the image associated with this article. It is added to the
108 // imageContainer only if there is an image to display, hiding the no-image
109 // icon.
110 @property(nonatomic, strong) UIImageView* contentImageView;
111
112 // Applies the constraints on the elements. Called in the init.
113 - (void)applyConstraints;
114
115 @end
116
117 @implementation ContentSuggestionsArticleCell
118
119 @synthesize titleLabel = _titleLabel;
120 @synthesize subtitleLabel = _subtitleLabel;
121 @synthesize imageContainer = _imageContainer;
122 @synthesize noImageIcon = _noImageIcon;
123 @synthesize publisherLabel = _publisherLabel;
124 @synthesize contentImageView = _contentImageView;
125 @synthesize faviconView = _faviconView;
126
127 - (instancetype)initWithFrame:(CGRect)frame {
128 self = [super initWithFrame:frame];
129 if (self) {
130 _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
131 _subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
132 _imageContainer = [[UIView alloc] initWithFrame:CGRectZero];
133 _noImageIcon = [[UIImageView alloc] initWithFrame:CGRectZero];
134 _publisherLabel = [[UILabel alloc] initWithFrame:CGRectZero];
135 _contentImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
136 _faviconView = [[FaviconViewNew alloc] init];
137
138 _titleLabel.numberOfLines = 2;
139 _subtitleLabel.numberOfLines = 2;
140 [_subtitleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh
141 forAxis:UILayoutConstraintAxisVertical];
142 [_titleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh
143 forAxis:UILayoutConstraintAxisVertical];
144
145 _contentImageView.contentMode = UIViewContentModeScaleAspectFill;
146 _contentImageView.clipsToBounds = YES;
147 _contentImageView.hidden = YES;
148
149 _imageContainer.translatesAutoresizingMaskIntoConstraints = NO;
150 _noImageIcon.translatesAutoresizingMaskIntoConstraints = NO;
151 _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
152 _subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
153 _publisherLabel.translatesAutoresizingMaskIntoConstraints = NO;
154 _contentImageView.translatesAutoresizingMaskIntoConstraints = NO;
155 _faviconView.translatesAutoresizingMaskIntoConstraints = NO;
156
157 [self.contentView addSubview:_imageContainer];
158 [self.contentView addSubview:_titleLabel];
159 [self.contentView addSubview:_subtitleLabel];
160 [self.contentView addSubview:_publisherLabel];
161 [self.contentView addSubview:_faviconView];
162
163 [_imageContainer addSubview:_noImageIcon];
164 [_imageContainer addSubview:_contentImageView];
165
166 _imageContainer.backgroundColor =
167 [UIColor colorWithWhite:kNoImageBackgroundWhite alpha:1];
168 _noImageIcon.image = [[UIImage imageNamed:kNoImageIconName]
169 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
170 [_noImageIcon
171 setTintColor:[UIColor colorWithWhite:kNoImageIconWhite alpha:1]];
172
173 _titleLabel.font = [MDCTypography subheadFont];
174 _subtitleLabel.font = [MDCTypography body1Font];
175 _publisherLabel.font = [MDCTypography captionFont];
176 _faviconView.font = [[MDCTypography fontLoader] mediumFontOfSize:10];
177
178 _subtitleLabel.textColor = [[MDCPalette greyPalette] tint700];
179 _publisherLabel.textColor = [[MDCPalette greyPalette] tint700];
180
181 [self applyConstraints];
182 }
183 return self;
184 }
185
186 - (void)setContentImage:(UIImage*)image {
187 if (!image) {
188 self.contentImageView.hidden = YES;
189 return;
190 }
191
192 self.contentImageView.image = image;
193
194 self.contentImageView.alpha = 0;
195 self.contentImageView.hidden = NO;
196
197 [UIView animateWithDuration:kAnimationDuration
198 animations:^{
199 self.contentImageView.alpha = 1;
200 }];
201 }
202
203 - (void)setPublisherName:(NSString*)publisherName date:(base::Time)publishDate {
204 NSDate* date = [NSDate dateWithTimeIntervalSince1970:publishDate.ToDoubleT()];
205 NSString* dateString =
206 [NSDateFormatter localizedStringFromDate:date
207 dateStyle:NSDateFormatterMediumStyle
208 timeStyle:NSDateFormatterNoStyle];
209
210 self.publisherLabel.text = AdjustStringForLocaleDirection(
211 [NSString stringWithFormat:@"%@ - %@.", publisherName, dateString]);
212 }
213
214 - (void)prepareForReuse {
215 self.contentImageView.hidden = YES;
216 }
217
218 #pragma mark - UIView
219
220 // Implements -layoutSubviews as per instructions in documentation for
221 // +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:].
222 - (void)layoutSubviews {
223 [super layoutSubviews];
224
225 // Adjust the text label preferredMaxLayoutWidth when the parent's width
226 // changes, for instance on screen rotation.
227 CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds);
228
229 self.titleLabel.preferredMaxLayoutWidth =
230 parentWidth - kImageSize - 3 * kStandardSpacing;
231 self.subtitleLabel.preferredMaxLayoutWidth =
232 parentWidth - kImageSize - 3 * kStandardSpacing;
233 self.publisherLabel.preferredMaxLayoutWidth =
234 parentWidth - kFaviconSize - kSmallSpacing - 2 * kStandardSpacing;
235
236 // Re-layout with the new preferred width to allow the label to adjust its
237 // height.
238 [super layoutSubviews];
239 }
240
241 #pragma mark - Private
242
243 - (void)applyConstraints {
244 [NSLayoutConstraint activateConstraints:@[
245 [_imageContainer.widthAnchor constraintEqualToConstant:kImageSize],
246 [_imageContainer.heightAnchor
247 constraintEqualToAnchor:_imageContainer.widthAnchor],
248 [_imageContainer.topAnchor constraintEqualToAnchor:_titleLabel.topAnchor],
249
250 // Publisher.
251 [_publisherLabel.topAnchor
252 constraintGreaterThanOrEqualToAnchor:_imageContainer.bottomAnchor
253 constant:kStandardSpacing],
254 [_publisherLabel.topAnchor
255 constraintGreaterThanOrEqualToAnchor:_subtitleLabel.bottomAnchor
256 constant:kStandardSpacing],
257 [_publisherLabel.bottomAnchor
258 constraintLessThanOrEqualToAnchor:self.contentView.bottomAnchor
259 constant:-kStandardSpacing],
260
261 // Favicon.
262 [_faviconView.topAnchor
263 constraintGreaterThanOrEqualToAnchor:_imageContainer.bottomAnchor
264 constant:kStandardSpacing],
265 [_faviconView.topAnchor
266 constraintGreaterThanOrEqualToAnchor:_subtitleLabel.bottomAnchor
267 constant:kStandardSpacing],
268 [_faviconView.centerYAnchor
269 constraintEqualToAnchor:_publisherLabel.centerYAnchor],
270 [_faviconView.bottomAnchor
271 constraintLessThanOrEqualToAnchor:self.contentView.bottomAnchor
272 constant:-kStandardSpacing],
273 [_faviconView.heightAnchor constraintEqualToConstant:kFaviconSize],
274 [_faviconView.widthAnchor
275 constraintEqualToAnchor:_faviconView.heightAnchor],
276
277 // No image icon.
278 [_noImageIcon.centerXAnchor
279 constraintEqualToAnchor:_imageContainer.centerXAnchor],
280 [_noImageIcon.centerYAnchor
281 constraintEqualToAnchor:_imageContainer.centerYAnchor],
282 [_noImageIcon.widthAnchor constraintEqualToConstant:kIconSize],
283 [_noImageIcon.heightAnchor constraintEqualToAnchor:_noImageIcon.widthAnchor]
284 ]];
285
286 AddSameConstraints(_contentImageView, _imageContainer);
287
288 ApplyVisualConstraintsWithMetrics(
289 @[
290 @"H:|-(space)-[title]-(space)-[image]-(space)-|",
291 @"H:|-(space)-[text]-(space)-[image]",
292 @"V:|-(space)-[title]-[text]",
293 @"H:|-(space)-[favicon]-(small)-[publish]-(space)-|",
294 ],
295 @{
296 @"image" : _imageContainer,
297 @"title" : _titleLabel,
298 @"text" : _subtitleLabel,
299 @"publish" : _publisherLabel,
300 @"favicon" : _faviconView,
301 },
302 @{ @"space" : @(kStandardSpacing),
303 @"small" : @(kSmallSpacing) });
304 }
305
306 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698