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

Side by Side Diff: ios/chrome/browser/ui/sad_tab/sad_tab_view.mm

Issue 2589583003: Upstream Chrome on iOS source code [7/11]. (Closed)
Patch Set: Created 4 years 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
« no previous file with comments | « ios/chrome/browser/ui/sad_tab/sad_tab_view.h ('k') | ios/chrome/browser/ui/settings/README.md » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/sad_tab/sad_tab_view.h"
6
7 #import "base/ios/weak_nsobject.h"
8 #include "base/logging.h"
9 #include "base/mac/scoped_block.h"
10 #include "base/mac/scoped_nsobject.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "components/grit/components_scaled_resources.h"
13 #include "components/strings/grit/components_strings.h"
14 #include "ios/chrome/browser/chrome_url_constants.h"
15 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
16 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
17 #import "ios/chrome/browser/ui/commands/open_url_command.h"
18 #include "ios/chrome/browser/ui/rtl_geometry.h"
19 #include "ios/chrome/browser/ui/ui_util.h"
20 #import "ios/chrome/browser/ui/url_loader.h"
21 #import "ios/chrome/browser/ui/util/label_link_controller.h"
22 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate rialButtons.h"
23 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
24 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoF ontLoader.h"
25 #include "ios/web/public/interstitials/web_interstitial.h"
26 #include "ios/web/public/web_state/web_state.h"
27 #import "net/base/mac/url_conversions.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/gfx/image/image.h"
31
32 namespace {
33 // Color constants.
34 const CGFloat kBackgroundColorBrightness = 247.0f / 255.0f;
35 const CGFloat kTitleLabelTextColorBrightness = 22.0f / 255.0f;
36 const CGFloat kMessageLabelTextColorBrightness = 80.0f / 255.0f;
37 // Layout constants.
38 const UIEdgeInsets kLayoutInsets = {24.0f, 24.0f, 24.0f, 24.0f};
39 const CGFloat kLayoutBoundsMaxWidth = 600.0f;
40 const CGFloat kContainerViewLandscapeTopPadding = 22.0f;
41 const CGFloat kTitleLabelTopPadding = 26.0f;
42 const CGFloat kMessageLabelTopPadding = 16.0f;
43 const CGFloat kHelpLabelTopPadding = 16.0f;
44 const CGFloat kReloadButtonHeight = 48.0f;
45 const CGFloat kReloadButtonTopPadding = 16.0f;
46 // Label font sizes.
47 const CGFloat kTitleLabelFontSize = 23.0f;
48 const CGFloat kMessageLabelFontSize = 14.0f;
49 const CGFloat kHelpLabelFontSize = 14.0f;
50 } // namespace
51
52 @interface SadTabView () {
53 // The block called when |_reloadButton| is tapped.
54 base::mac::ScopedBlock<ProceduralBlock> _reloadHandler;
55 // Backing objects for properties of the same name.
56 base::scoped_nsobject<UIView> _containerView;
57 base::scoped_nsobject<UIImageView> _imageView;
58 base::scoped_nsobject<UILabel> _titleLabel;
59 base::scoped_nsobject<UILabel> _messageLabel;
60 base::scoped_nsobject<UILabel> _helpLabel;
61 base::scoped_nsobject<LabelLinkController> _helpLabelLinkController;
62 base::scoped_nsobject<MDCButton> _reloadButton;
63 }
64
65 // Container view that displays all other subviews.
66 @property(nonatomic, readonly) UIView* containerView;
67 // Displays the Sad Tab face.
68 @property(nonatomic, readonly) UIImageView* imageView;
69 // Displays the Sad Tab title.
70 @property(nonatomic, readonly) UILabel* titleLabel;
71 // Displays the Sad Tab message.
72 @property(nonatomic, readonly) UILabel* messageLabel;
73 // Displays the Sad Tab help message.
74 @property(nonatomic, readonly) UILabel* helpLabel;
75 // Button used to trigger a reload.
76 @property(nonatomic, readonly) UIButton* reloadButton;
77
78 // The bounds of |containerView|, with a height updated to CGFLOAT_MAX to allow
79 // text to be laid out using as many lines as necessary.
80 @property(nonatomic, readonly) CGRect containerBounds;
81
82 // Subview layout methods. Must be called in the following order, as subsequent
83 // layouts reference the values set in previous functions.
84 - (void)layoutImageView;
85 - (void)layoutTitleLabel;
86 - (void)layoutMessageLabel;
87 - (void)layoutHelpLabel;
88 - (void)layoutReloadButton;
89 - (void)layoutContainerView;
90
91 // The action selector for |_reloadButton|.
92 - (void)handleReloadButtonTapped;
93
94 // Returns the desired background color.
95 + (UIColor*)sadTabBackgroundColor;
96
97 @end
98
99 #pragma mark - SadTabView
100
101 @implementation SadTabView
102
103 - (instancetype)initWithReloadHandler:(ProceduralBlock)reloadHandler {
104 self = [super initWithFrame:CGRectZero];
105 if (self) {
106 DCHECK(reloadHandler);
107 _reloadHandler.reset([reloadHandler copy]);
108 self.backgroundColor = [[self class] sadTabBackgroundColor];
109 }
110 return self;
111 }
112
113 - (instancetype)init {
114 NOTREACHED();
115 return nil;
116 }
117
118 - (instancetype)initWithFrame:(CGRect)frame {
119 NOTREACHED();
120 return nil;
121 }
122
123 - (instancetype)initWithCoder:(NSCoder*)aDecoder {
124 NOTREACHED();
125 return nil;
126 }
127
128 #pragma mark Accessors
129
130 - (UIView*)containerView {
131 if (!_containerView) {
132 _containerView.reset([[UIView alloc] initWithFrame:CGRectZero]);
133 [_containerView setBackgroundColor:self.backgroundColor];
134 }
135 return _containerView;
136 }
137
138 - (UIImageView*)imageView {
139 if (!_imageView) {
140 ui::ResourceBundle& resourceBundle =
141 ui::ResourceBundle::GetSharedInstance();
142 UIImage* image =
143 resourceBundle.GetNativeImageNamed(IDR_CRASH_SAD_TAB).ToUIImage();
144 _imageView.reset([[UIImageView alloc] initWithImage:image]);
145 [_imageView setBackgroundColor:self.backgroundColor];
146 }
147 return _imageView.get();
148 }
149
150 - (UILabel*)titleLabel {
151 if (!_titleLabel) {
152 _titleLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]);
153 [_titleLabel setBackgroundColor:self.backgroundColor];
154 [_titleLabel setText:base::SysUTF8ToNSString(
155 l10n_util::GetStringUTF8(IDS_SAD_TAB_TITLE))];
156 [_titleLabel setLineBreakMode:NSLineBreakByWordWrapping];
157 [_titleLabel setNumberOfLines:0];
158 [_titleLabel
159 setTextColor:[UIColor colorWithWhite:kTitleLabelTextColorBrightness
160 alpha:1.0]];
161 [_titleLabel setFont:[[MDFRobotoFontLoader sharedInstance]
162 regularFontOfSize:kTitleLabelFontSize]];
163 }
164 return _titleLabel.get();
165 }
166
167 - (UILabel*)messageLabel {
168 if (!_messageLabel) {
169 _messageLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]);
170 [_messageLabel setBackgroundColor:self.backgroundColor];
171 std::string messageText = l10n_util::GetStringUTF8(IDS_SAD_TAB_MESSAGE);
172 [_messageLabel setText:base::SysUTF8ToNSString(messageText)];
173 [_messageLabel setLineBreakMode:NSLineBreakByWordWrapping];
174 [_messageLabel setNumberOfLines:0];
175 [_messageLabel
176 setTextColor:[UIColor colorWithWhite:kMessageLabelTextColorBrightness
177 alpha:1.0]];
178 [_messageLabel setFont:[[MDFRobotoFontLoader sharedInstance]
179 regularFontOfSize:kMessageLabelFontSize]];
180 }
181 return _messageLabel.get();
182 }
183
184 - (UILabel*)helpLabel {
185 if (!_helpLabel) {
186 _helpLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]);
187 [_helpLabel setBackgroundColor:self.backgroundColor];
188 [_helpLabel setNumberOfLines:0];
189 [_helpLabel setFont:[[MDFRobotoFontLoader sharedInstance]
190 regularFontOfSize:kHelpLabelFontSize]];
191 [_helpLabel
192 setTextColor:[UIColor colorWithWhite:kMessageLabelTextColorBrightness
193 alpha:1.0]];
194 // Fetch help text.
195 base::string16 helpLinkText(
196 l10n_util::GetStringUTF16(IDS_SAD_TAB_HELP_LINK));
197 NSString* helpText = base::SysUTF16ToNSString(
198 l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE, helpLinkText));
199 [_helpLabel setText:helpText];
200 // Create link controller.
201 base::WeakNSObject<SadTabView> weakSelf(self);
202 _helpLabelLinkController.reset([[LabelLinkController alloc]
203 initWithLabel:_helpLabel
204 action:^(const GURL& url) {
205 base::scoped_nsobject<OpenUrlCommand> openCommand(
206 [[OpenUrlCommand alloc] initWithURLFromChrome:url]);
207 [weakSelf chromeExecuteCommand:openCommand];
208 }]);
209 [_helpLabelLinkController
210 setLinkFont:[[MDFRobotoFontLoader sharedInstance]
211 boldFontOfSize:kHelpLabelFontSize]];
212 [_helpLabelLinkController setLinkUnderlineStyle:NSUnderlineStyleSingle];
213 NSRange linkRange =
214 [helpText rangeOfString:base::SysUTF16ToNSString(helpLinkText)];
215 DCHECK_NE(linkRange.location, static_cast<NSUInteger>(NSNotFound));
216 DCHECK_NE(linkRange.length, 0U);
217 [_helpLabelLinkController addLinkWithRange:linkRange
218 url:GURL(kCrashReasonURL)];
219 }
220 return _helpLabel.get();
221 }
222
223 - (UIButton*)reloadButton {
224 if (!_reloadButton) {
225 _reloadButton.reset([[MDCFlatButton alloc] init]);
226 [_reloadButton setBackgroundColor:[[MDCPalette cr_bluePalette] tint500]
227 forState:UIControlStateNormal];
228 [_reloadButton setBackgroundColor:[[MDCPalette greyPalette] tint500]
229 forState:UIControlStateDisabled];
230 [_reloadButton setCustomTitleColor:[UIColor whiteColor]];
231 [_reloadButton setUnderlyingColorHint:[UIColor blackColor]];
232 [_reloadButton setInkColor:[UIColor colorWithWhite:1 alpha:0.2f]];
233 NSString* title = base::SysUTF8ToNSString(
234 l10n_util::GetStringUTF8(IDS_SAD_TAB_RELOAD_LABEL));
235 [_reloadButton setTitle:title forState:UIControlStateNormal];
236 [_reloadButton setTitleColor:[UIColor whiteColor]
237 forState:UIControlStateNormal];
238 [_reloadButton addTarget:self
239 action:@selector(handleReloadButtonTapped)
240 forControlEvents:UIControlEventTouchUpInside];
241 }
242 return _reloadButton.get();
243 }
244
245 - (CGRect)containerBounds {
246 CGFloat containerWidth = std::min(
247 CGRectGetWidth(self.bounds) - kLayoutInsets.left - kLayoutInsets.right,
248 kLayoutBoundsMaxWidth);
249 return CGRectMake(0.0, 0.0, containerWidth, CGFLOAT_MAX);
250 }
251
252 #pragma mark Layout
253
254 - (void)willMoveToSuperview:(nullable UIView*)newSuperview {
255 [super willMoveToSuperview:newSuperview];
256
257 if (self.containerView.superview) {
258 DCHECK_EQ(self.containerView.superview, self);
259 return;
260 }
261
262 [self addSubview:self.containerView];
263 [self.containerView addSubview:self.imageView];
264 [self.containerView addSubview:self.titleLabel];
265 [self.containerView addSubview:self.messageLabel];
266 [self.containerView addSubview:self.helpLabel];
267 }
268
269 - (void)layoutSubviews {
270 [super layoutSubviews];
271
272 [self layoutImageView];
273 [self layoutTitleLabel];
274 [self layoutMessageLabel];
275 [self layoutHelpLabel];
276 [self layoutReloadButton];
277 [self layoutContainerView];
278 }
279
280 - (CGSize)sizeThatFits:(CGSize)size {
281 return size;
282 }
283
284 - (void)layoutImageView {
285 LayoutRect imageViewLayout = LayoutRectZero;
286 imageViewLayout.boundingWidth = CGRectGetWidth(self.containerBounds);
287 imageViewLayout.size = self.imageView.bounds.size;
288 self.imageView.frame =
289 AlignRectOriginAndSizeToPixels(LayoutRectGetRect(imageViewLayout));
290 }
291
292 - (void)layoutTitleLabel {
293 CGRect containerBounds = self.containerBounds;
294 LayoutRect titleLabelLayout = LayoutRectZero;
295 titleLabelLayout.boundingWidth = CGRectGetWidth(containerBounds);
296 titleLabelLayout.size = [self.titleLabel sizeThatFits:containerBounds.size];
297 titleLabelLayout.position.originY =
298 CGRectGetMaxY(self.imageView.frame) + kTitleLabelTopPadding;
299 self.titleLabel.frame =
300 AlignRectOriginAndSizeToPixels(LayoutRectGetRect(titleLabelLayout));
301 }
302
303 - (void)layoutMessageLabel {
304 CGRect containerBounds = self.containerBounds;
305 LayoutRect messageLabelLayout = LayoutRectZero;
306 messageLabelLayout.boundingWidth = CGRectGetWidth(containerBounds);
307 messageLabelLayout.size =
308 [self.messageLabel sizeThatFits:containerBounds.size];
309 messageLabelLayout.position.originY =
310 CGRectGetMaxY(self.titleLabel.frame) + kMessageLabelTopPadding;
311 self.messageLabel.frame =
312 AlignRectOriginAndSizeToPixels(LayoutRectGetRect(messageLabelLayout));
313 }
314
315 - (void)layoutHelpLabel {
316 CGRect containerBounds = self.containerBounds;
317 LayoutRect helpLabelLayout = LayoutRectZero;
318 helpLabelLayout.boundingWidth = CGRectGetWidth(containerBounds);
319 helpLabelLayout.size = [self.helpLabel sizeThatFits:containerBounds.size];
320 helpLabelLayout.position.originY =
321 CGRectGetMaxY(self.messageLabel.frame) + kHelpLabelTopPadding;
322 self.helpLabel.frame =
323 AlignRectOriginAndSizeToPixels(LayoutRectGetRect(helpLabelLayout));
324 }
325
326 - (void)layoutReloadButton {
327 CGRect containerBounds = self.containerBounds;
328 BOOL isIPadIdiom = IsIPadIdiom();
329 BOOL isPortrait = IsPortrait();
330 BOOL shouldAddReloadButtonToContainer = isIPadIdiom || !isPortrait;
331 LayoutRect reloadButtonLayout = LayoutRectZero;
332 reloadButtonLayout.size =
333 isIPadIdiom
334 ? [self.reloadButton sizeThatFits:CGSizeZero]
335 : CGSizeMake(CGRectGetWidth(containerBounds), kReloadButtonHeight);
336 if (shouldAddReloadButtonToContainer) {
337 // Right-align reloadButton and add it below helpLabel when adding it to
338 // the containerView.
339 if (self.reloadButton.superview != self.containerView)
340 [self.containerView addSubview:self.reloadButton];
341 reloadButtonLayout.boundingWidth = CGRectGetWidth(containerBounds);
342 reloadButtonLayout.position = LayoutRectPositionMake(
343 CGRectGetWidth(containerBounds) - reloadButtonLayout.size.width,
344 CGRectGetMaxY(self.helpLabel.frame) + kReloadButtonTopPadding);
345 } else {
346 // Bottom-align the reloadButton with the bounds specified by kLayoutInsets.
347 if (self.reloadButton.superview != self)
348 [self addSubview:self.reloadButton];
349 reloadButtonLayout.boundingWidth = CGRectGetWidth(self.bounds);
350 reloadButtonLayout.position = LayoutRectPositionMake(
351 UIEdgeInsetsGetLeading(kLayoutInsets),
352 CGRectGetMaxY(self.bounds) - kLayoutInsets.bottom -
353 reloadButtonLayout.size.height);
354 }
355 self.reloadButton.frame =
356 AlignRectOriginAndSizeToPixels(LayoutRectGetRect(reloadButtonLayout));
357 }
358
359 - (void)layoutContainerView {
360 UIView* bottomSubview = self.reloadButton.superview == self.containerView
361 ? self.reloadButton
362 : self.helpLabel;
363 CGSize containerSize = CGSizeMake(CGRectGetWidth(self.containerBounds),
364 CGRectGetMaxY(bottomSubview.frame));
365 CGFloat containerOriginX =
366 (CGRectGetWidth(self.bounds) - containerSize.width) / 2.0f;
367 CGFloat containerOriginY = 0.0f;
368 if (IsIPadIdiom()) {
369 // Center the containerView on iPads.
370 containerOriginY =
371 (CGRectGetHeight(self.bounds) - containerSize.height) / 2.0f;
372 } else if (IsPortrait()) {
373 // Align containerView to a quarter of the view height on portrait iPhones.
374 containerOriginY =
375 (CGRectGetHeight(self.bounds) - containerSize.height) / 4.0f;
376 } else {
377 // Top-align containerView on landscape iPhones.
378 containerOriginY = kContainerViewLandscapeTopPadding;
379 }
380 self.containerView.frame = AlignRectOriginAndSizeToPixels(
381 CGRectMake(containerOriginX, containerOriginY, containerSize.width,
382 containerSize.height));
383 }
384
385 #pragma mark Util
386
387 - (void)handleHelpLabelLinkButtonTapped {
388 base::scoped_nsobject<OpenUrlCommand> openCommand(
389 [[OpenUrlCommand alloc] initWithURLFromChrome:GURL(kCrashReasonURL)]);
390 [self chromeExecuteCommand:openCommand];
391 }
392
393 - (void)handleReloadButtonTapped {
394 _reloadHandler.get()();
395 }
396
397 + (UIColor*)sadTabBackgroundColor {
398 return [UIColor colorWithWhite:kBackgroundColorBrightness alpha:1.0];
399 }
400
401 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/sad_tab/sad_tab_view.h ('k') | ios/chrome/browser/ui/settings/README.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698